石鑫华机器视觉网
引言
目前,以CCD技术为核心的图像获取设备可以分为两类:
1)由CCD摄像头、图像采集卡和计算机组成的图像采集系统,利用图像采集卡把CCD传来的模拟图像信号转换为数字图像信号并传送给计算机处理;
2)由CCD相机本身带有的数字化设备直接将数字图像信号通过端口传送给计算机。
其中前者作为经典的图像采集系统在图像采集的应用中一直居于主导地位[1],但是,性能较好的采集卡价格昂贵,同时由于需求不同,常常需要对采集卡进行二次开发,而大多采集卡生产厂家封装了自己的函数和链接库,因此在二次开发时对开发人员的专业素质要求较高。近年来随着CCD相机技术的不断进步,以数码相机为代表的第二类图像采集设备以其方便快捷、采集速度快、高分辨率、高性价比等特点受到人们的广泛关注,已经在一些领域取得了很好的应用。
对于第二类图像采集设备,因为是CCD相机直接提供数字信号,因此可以获得高品质的图像,但同时,也对图像数据的传输速率提出了较高的要求。一般CCD输出可以遵循RS-422、RS-644和IEEE1394等数字输出接口标准。其中,RS-422的数据传输速率比较低,不能满足大量图像数据传输的要求;而RS-644在进行传输数据时,必须外加图像采集卡,这样就增加了整个系统的造价。而IEEE1394不仅能够提供高速的数据速率,克服RS-422数据传输速率低的缺点,同时在和CCD相连的时候不需要外加图像采集卡[2]。
IEEE1394,又称FireWire(火线),是1987年Apple公司发布的一个高速串行总线标准。该标准在1995年被电气与电子工程师协会(IEEE)采纳,称之为IEEE1394。1995年的IEEE1394-1995其数据传输率为100/200/400Mbps,后来其改进版IEEE1394b的数据传输率可达到800Mbps,1.6Gbps及3.2Gbps。所以,IEEE1394总线是目前较最快的串行总线(目前是指2000年左右)。IEEE1394总线具有如下特点:(1)数字接口:数据以数字形式传输,不需数模转换,从而降低了设备的复杂性,保证了信号的质量;(2)即插即用;(3) 速度快,支持同步和异步两种数据传输模式;(4) 物理体积小,制造成本低,易于安装;(5) 价廉。基于这些特点,1394被广泛应用于多媒体领域,特别是数码摄像机。
目前,接触最多的是对图像采集卡的编程控制,而关于利用第二类图像采集设备进行图像采集时的编程方法介绍很少。因此,本文着重阐述在VC++平台下应用基于1394接口的第二类图像采集设备进行图像采集的编程过程。
1 图像采集系统的硬件组成及开发平台
本文中图像采集的硬件组成:工业数码相机,1394b卡和PC机。在PC机主机的空余PCI插槽上安装上系统所需的1394b卡,通过1394接口把相机在PC机并安装驱动程序,这样,本系统所需要的硬件环境就完成了。
使用的系统平台时Windows 2000,开发环境时Microsoft VC++6.0。
2 图像采集的实现
图像采集系统的编写,主要内容包括:人机交互界面、从CCD相机接收图像信号并保存、图像在采集界面显示及对相机的控制。以下将对其逐一阐述。
2.1 建立采集界面
对于采集界面,可以创建为对话框形式,也可以采用文档结构,本文采用后者:
1)生成一个MFC AppWizard(exe)多文档应用程序框架(应用程序名称:PictureTest)。
2)连接相机的动态链接库(因为要控制相机采图,所以会用到相机的库函数)。找到相机安装的目录文件,把include文件夹的文件路径加入到Project->Setting->C/C++->;preprocessor->AdditiONal include directories的编辑框中;把lib文件夹的文件路径加入到Project->Setting->Link->Input->Additional library path的编辑框中,同时在…->Input->Object/library modules编辑框中输入pgrflycapture.lib pgrflycapturegui.lib。
3)包含相机控制类的头文件,在工程中的CPictureTestDoc.h文件中加入头文件:
#include <pgrflycapture.h>
#include <pgrcAMEragui.h>
并定义共有变量:
FlyCaptureContext context; //相机功能句柄
CameraGUIContext m_guicontext; //图形用户界面(GUI)句柄
4)用相机采图时,首先需要对其初始化,这部分工作我们希望在应用程序打开时由系统自己完成。在工程中的CPictureTestDoc.cpp文件中对相机进行初始化:
首先,在构造函数中对定义的功能句柄初始化:
context=NULL; //相机功能句柄初始化
m_guicontext=NULL; //图像用户界面句柄初始化
然后,在OnNewDocument()函数中连接相机并初始化:
flycaptureCreateContext( &context );//连接相机
guierror=pgrcamguiCreateContext( &m_guicontext );//创建GUI连接
flycaptureInitialize( context, _CAMERA_INDEX );//相机初始化
2.2 图像抓取
在一些自动化系统中,可能在多处用到抓图代码,因此为增强程序的可读性,减少编程代码,我们编写一个功能函数,由它来完成抓图并保存功能,这样在需要的时候,直接调用函数即可。在CPictureTestDoc.cpp文件中加入功能函数PictureGrab(),用它来实现图像抓取,其核心代码如下:
flycaptureStart( context,
FLYCAPTURE_VIDEOMODE_ANY,
FLYCAPTURE_FRAMERATE_ANY );//相机开启,其中三个参数分别为:相机功能句柄,视频模式,帧频
flycaptureGrabImage2( context, &image );//抓图,image是图像在内存中的存放地址
flycaptureConvertImage( context, &image, &imageConverted );//图像格式转换,imageConverted为转换后图像在内存中的地址
flycaptureSaveImage(context,&imageConverted,("TestPicture.bmp"),SAVE_FORMAT_C );//保存图像,TestPicture.bmp为图像保存名称,SAVE_FORMAT_C为图像保存格式,即BMP格式
flycaptureStop( context );//停止相机
通过上述程序抓到的图像,保存在本工程文件夹中,这样,在后续的图像处理时,可以在程序中直接通过文件名访问图像文件,而不需要添加路径,简化了程序代码。
2.3 图像显示
Windows位图由两种:DDB和DIB。前者依赖于设备(Device Dependent Bitmap),与MFC 6.0中的CBitmap类相对应,它们在内存中的结构和位置依赖于管理它们的设备驱动。DIB是一种“格式”,它可以存放在内存中,也可以存储成文件,即常见的BMP文件。Visual C++的MFC中,以CBitmap类代表DDB图像,极大地方便了编程人员对DDB的使用。然而通常情况下,没有人会把DDB图像存储成文件,因此我们使用更多的是DIB,遗憾的是MFC对于DIB的支持几乎可以说是没有,因此在编制图像处理的程序时,有必要设计可以重复使用的类CDib,专门用来处理DIB[4](关于CDib,读者可以参阅相关书目,本文不再累述)。本文中,为了方便后续的图像处理,在图像显示时采用类CDib技术。因为在实际应用中,我们往往需要图像的连续读入,因此本文直接采用文件名读入图像,这样可以使采集的图像实时的显示。
首先,定义类CDib,并在CPictureTestDoc.h中定义共有变量:
CDib m_dib;//CDib类对象,用于位图文件的读写
然后,在CPictureTestDoc.cpp文件中添加功能函数:PictureRead(),在其中加入代码:
CString strPathName;
strPathName = _T("TestPicture.bmp");
if (m_dib.Read(strPathName) == TRUE)
{
SetModifiedFlag(FALSE); // start off with unmodified
return ;
}
并在CPictureTestView.cpp文件中的OnDraw(CDC* pDC)函数中,加入如下代码:
CPictureTestDoc* pDoc = GetDocument();
CDib *pDib=pDoc->GetPDib();//返回m_dib的指针
CSize sizeFileDib = pDib->GetDimensions();//获取DIB的尺寸
pDib->Draw(pDC, CPoint(0, 0), sizeFileDib); //显示DIB
在OnInitialUpdate()函数中设置滚动窗口:
CDib *pDib=pDoc->GetPDib();//获取DIB的指针
if(pDib!=NULL)
SetScrollSizes(MM_TEXT, pDib->GetDimensions());//根据DIB尺寸设置视窗大小
最后,添加图像采集命令菜单,其响应函数为:
void CPictureTestView::OnTestStart()
{
CPictureTestDoc * pDoc = GetDocument();
pDoc->;pictureGrab ();//抓图
pDoc->;pictureRead();//把图像读入内存
OnInitialUpdate();//设置滚动窗口
}
编译通过后,单击图像采集命令,即可实时获取图像。
图1 图像采集实例
Fig.1 The example of image acquisition
2.4 相机设置
在图像采集时,我们往往需要对相机的参数如图像格式、分辨率、帧频等进行设定,同时,为了获取高品质图像,我们还需要做白平衡调节。当然,这些参数的设定我们可以在相机初始化时由代码实现,但是,在实际应用中,为了达到最佳效果,我们需要多次调试才能达成,如果采用修改代码的方法,调试过程会很麻烦。数码相机一般都有设置菜单,我们要做的就是,通过代码来调用相机的设置菜单,设置好参数后,参数会自动保存并加载。这样,调试的时候会方便很多。创建相机设置菜单命令,其响应函数如下:
void CPictureTestDoc::OnTestCameraset()
{
pgrcamguiToggleSettingsWindowState(
m_guicontext, AfxGetApp()->m_pMainWnd->GetSafeHwnd() );//相机设置对话框
}
图2 相机参数设置界面
Fig.2 Interface for setting the parameter of the camera
3 结 论
本文实现的图像采集系统可通过1394接口对数码机进行格式/模式/帧率的设置,光学参数的设定,采集画面的实时显示,而且能够对摄像机进行自动控制,系统稳定可靠,利用它可以完成一些复杂项目中的实时连续的图像采集过程,如高速公路车辆和车牌的自动识别管理系统、工业生产中的产品外包装检测系统等,具有很大的实用性.