MIL

MIL
MIL

https://www.360docs.net/doc/5e8536409.html, 编程环境设置

MIL全称为Matrox Imaging Library,由加拿大Matrox公司开发;MIL软件包是一个独立于硬件的、含有多个标准模块或组件的32位图像库,可以对图像进行采集、处理、分析、显示和存取操作,其功能覆盖图像领域的所有方面,使用起来也相当简单和方便;MIL-Lite是MIL的子集,含有MIL的部分模块,可以进行图像的采集、显示、存取操作,还可以在图像上进行图形操作及LUT变换等;MIL/MIL-Lite支持Matrox公司所有采集卡,如果应用程序采用其它公司的采集卡,则不能使用MIL/MIL-Lite的采集功能,但应用程序可以使用MIL/MIL-Lite的其它功能。

那么要采用MIL进行应用程序开发首先就要设置开发环境,放好动态链接库位置,链接好导入库文件,引入必要的.h头文件。

安装完MIL后(一般采取默认安装,即安装路径为C:\Program Files\Matrox Imaging),如下图

其中Drivers为驱动文件,Images为示例图片文件夹,Intellicam为Intellicam软件,Mil 为开发用的文件,Tools为辅助开发的一些工具,MILControlCenter.hta为控制中心,MILInstall.log为安装日志

因为我们要进行开发,所以进到Mil文件夹中,如下

其中DLL为MIL的各个模块的动态链接库,DOC为帮助文档,Examples为VC示例,Include 为必要的头文件,LIB为导入库文件

那么为了进行开发首先应该将Dll文件加入系统Path路径,便于编译时找到相应模块的Dll,这一步安装MIL时已经默认做好了,若意外没有设置,则可如下手工设置

然后将头文件加入系统路径,如下图(注意要把Include和Include\mildyn都加进来,VC 不会自己到include包含的文件夹中去搜索。)

然后,再加入导入库的路径lib

为了保证设置一次,以后再写mil程序时即可用,请保证当前没有打开任何工程和文件,否则VC即认为当前加入系统头文件路径只是针对当前工程,这个设置被写到当前文件的设置文件中(应该是.dsp文件),而并不是记录到VC软件中。这样当你新建另一个MIL工程后还得重新设置

以上设置完以后,新建一MIL工程,要想用MIL功能,进行动态链接如下

#pragma comment(lib, "mil.lib")

#include

在mfc中一般加在staAfx.h文件中

其中mil.lib包含mil的基本功能,要想用其他的功能可以类似的引入(如,#pragma comment(lib, "milim.lib"));mil.h实际上包含了很多其他模块的头文件,这里实际上同时引入了其他各个模块的头文件,当然也可以只引入需要的头文件

这样就可以用MIL进行开发了

当然这只是这其中的一种办法,你也可以将dll,lib,h文件全部拷贝到当前文件夹,再来开发应用程序,但本文这种方法简单易行,开发方便

附加说明:引入DLL路径除了加入到系统Path变量中,还可以直接同VC添加LIB和INCLUDE目录一样添加DLL目录,效果是一样的。推荐使用添加到Path的方法,这样命令行编译不会出错。

https://www.360docs.net/doc/5e8536409.html,开发基础概念和步骤

相对于开源的Open CV来说商业化的MIL开发相对容易,只需要遵循特定的步骤即可以完成自己的开发。但是对于MIL中的一些基础概念还是要理解,不然可能在后面查看函数帮助时会混淆一些概念。

MIL中有五大基本对象(这里的对象和C++的对象不一样额,不过也可以看成一样的,猜想也是一个结构体):Application、System、Display、Digtizer、Buffer。如下图是这5大基本对象的一个简单关系图。

Application

Application指的是你自己开发的一个应用程序,一般应用程序同一时刻只存在一个Application对象。主要用它来提供一个用于控制和执行MIL应用程序的基本环境。System

System代表为一个包含CPU或GPU、内存或显存和图像控制器的单元分配的一个虚拟访问对象,例如一块Matrox图像板卡,一个电脑主机都可以被分配为一个System。System 能够通过加上相机和显示器来采集、保存和显示。每个Application下可以包含多个System,这就好比一台电脑可以插上多块Matrox图像板卡。

Buffer

Buffer对应一块内存,可以对它赋予不同的属性用来对图像作相应处理,如存储、显示、采集、处理,只有赋予了对应的属性的Buffer才能用于对应操作,只赋予了保存属性的Buffer 是不能用于显示的。

Digtizer

Digtizer对应相机。它用于相机的采集和相机属性的调整等,和相机有关的操作都是靠它来完成。

Display

Display对应显示器。所有和显示的操作都是靠它来完成。这个在手册中提到了两种Display:一种是MIL内建的用于演示的Display叫Auxiliary Display,它不适用于Windows Desktop,主要用于和Matrox显卡配套使用的Screen,一般用不上,不予讨论;另一种是叫Windowed Display,一种是MIL用于演示的Display,不需要选择要显示的窗口句柄,默认分配的Display 对象是此种display,另一种是用户选择要显示的窗口句柄,这个需要你自己选择在哪个windows窗体上显示对应的Buffer图像内容。

值得注意的是:只要你的电脑配置足够好,内存足够大,每一个System下可以包含任意数量的Digtizer、Display和Buffer。但是,在同一时刻用于实际显示的Buffer和Display只能有一个,我的意思是尽管你可以分配多个,但是每一次你只能用一个,要用另一个的话你只需要做一个切换操作,这在后面多Buffer显示中会讲到。

下面我以MIL手册上做一下修改来讲解,下面的源代码(新建一个Win32 Console项目,复制代码到CPP文件中编译即可运行)演示了一个基本的MIL程序开发步骤。

[cpp]view plaincopyprint?

1.#include

2.#include

3.

4.#pragma comment(lib, "mil.lib")

5.

6.int main(int argc, char *argv[])

7.{

8. MIL_ID MilApplication, /* Application identifier. */

9. MilSystem, /* System identifier. */

10. MilDisplay, /* Display identifier. */

11. MilImage; /* Image buffer identifier. */

12.

13.//分配默认的应用

14. MappAllocDefault(M_SETUP, &MilApplication, &MilSystem, &MilDisplay, M_NU

LL, M_NULL);

15.

16.//分配显示的图像Buffer

17. MbufAlloc2d(MilSystem, 500, 500, M_DEF_IMAGE_TYPE, M_IMAGE+M_DISP, &MilI

mage);

18.

19./* 初始化Buffer,内存中绘制相应图像 */

20. MbufClear(MilImage, 0L);

21. MgraColor(M_DEFAULT, 255L);

22. MgraArcFill(M_DEFAULT, MilImage, 200L, 200L, 10L, 10L, 0.0, 360.0);

23. MgraText(M_DEFAULT, MilImage, 0L, 0L, " MIL ");

24.

25./* 图像Buffer内容显示到相应Display上,此后修改Buffer,Display自动刷新 */

26. MdispSelect(MilDisplay, MilImage);

27.

28./* 打印提示信息. */

29. printf("A circle was drawn in the displayed image buffer.\n");

30. printf("Press to end.\n");

31. getchar();

32.

33./* 释放图像Buffer. */

34. MbufFree(MilImage);

35.

36./* 释放默认应用分配的资源. */

37. MappFreeDefault(MilApplication, MilSystem, MilDisplay, M_NULL, M_NULL);

38.

39.return 0;

40.}

可以看到最开始分配了Mil的对象,每个对象分配后都有一个MIL_ID类型的标识变量,Application和System是至少要有的,由于有存储和显示图像的需求,还要分配Buffer和Display,没有采集图像的功能,所以不需要分配Digtizer。

最开始程序分配了系统默认的Application、System和Display,这里的Display类型就是前面提及的MIL内建的用于演示的display窗口。

博客中代码文件下载链接

https://www.360docs.net/doc/5e8536409.html,/detail/wenzhou1219/6420917

https://www.360docs.net/doc/5e8536409.html,/wenzhou1219/article/details/169410 97

https://www.360docs.net/doc/5e8536409.html,采集和实时显示

前面讲到的都是离线的图像获取方法,实际中我们做机器视觉都是在线采集图像和处理,处理结果决定了计算机要给出的控制信号如电机运动等,这样就实现了实时视觉反馈运动。MIL中的采集需要Matrox采集板卡的支持,本文中以实验室的Matrox Helios板卡为例讲解MIL的采集。

1.采集系统构成

谈到采集,首先必须理解一套完整的采集系统从硬件到软件的构成,下面采集系统示意图采用Matrox板卡、MIL软件,图中各种CPU、MCU、GPU交互通信的详细过程并没有表示出来,只是为了说明大概流程,实际过程中完整采集系统差别不大。(以后有时间我会考虑单独出一个机器视觉硬件系列博文,后话啦)

对照上图,简要说明一下采图过程:光源照射下,物体反射光经过相机镜头在相机CCD(或CMOS)芯片上,这个过程成称为Capture,相机的时序控制器控制间隔一定的时间将CCD 中的数据传输到相机的缓存Buffer中,这个过程称为Acquisition,注意如果这个Buffer的数据不及时取出来的话下次acquisition会覆盖以前的数据,相机连接到插入PCI-E接口上的Matrox板卡上,在板卡上的时序控制单元(Time control unit)控制从相机中Buffer中拿数据,这一过程称为Grab,从相机buffer中拿的还是模拟信号,在板卡中会通过A/D单

元做一个A/D转换,将拿到的数据转成相应量化的数值存到相应的MIL buffer中,这一过程称为Digtize。在这里Capture和Acquisition在相机(Camera)中完成输出的是模拟信号,这个相机是模拟相机,Grab和Digtize在相机采集板卡(Frame Grabber)中完成,一般这样的相机和板卡之间用的是Camera Link接口,也有用1394接口的,适用于高速采集的情况;也有相机将Capture、Acquisition、Grab、Digtize做在一起的,实际上这也是大多数普通工业相机(13fps-30fps)的做法,他们输出的是数字信号,称为数字相机,一般采用GigE 、1394或USB接口。注意这里我用红字标识的四个英文单词Capture、Acquisition、Grab、Digtize,他们都可以翻译为采集,英文有些单词意义近似但是有微妙的不同,用中文是没有办法明确的区分它们的意思,事实上,我们通常所说的采集是站在PC获取物体图像的角度来说的,是这四个过程的总称。

当我们在上位机(PC)中操作整个采集过程,MIL提供给我们用于采集的是分配的Digtizer 对象,对应Mdig开头函数。在分配Digitizer对象时要同时指明一个DCF(Device Configure File)文件,这个文件定义了Grab时的频率和分辨率等等,是非常重要的,简单来说就是相机时序控制器往相机Buffer存入数据的频率和板卡时序控制单元从相机Buffer中获取数据的频率必须有一个匹配关系。默认MIL安装时会让用户设置一个默认的DCF文件,分配Digtizer时默认使用这个文件,MIL提供了一系列对应相机的DCF文件,如果没有还可以在MIL Intellicam中自定义DCF文件,同一个相机,可以在定义Digtizer时候采用不同的DCF 文件改变采集的频率和采集的图像大小,如图中的Digtizer1和Digtizer2,如果想在定义了Digtizer以后实时调整DCF中对应的采集参数可以用MdigControl开头函数。

下面对照上图说明几个概念,对大家看手册有帮助:

Acquisition path:从Capture历经Acquisition、Grab到Digtize一条完整的过程,如图对于彩色相机有6条Acquisition path(RGB每一个算一个通道,即你可以把彩色相机当做单色相机来使),对于单色相机分别各有2条Acquisition path,每一条Acquisition path都必须包含一个Time control unit。每条Acquisition path上可连接若干Digtizer,如图中Digtizer1和Digitizer2,但是同一Acquisition path上一次只能有一个Digtizer工作,你可以预分配多个Digtizer,在需要的时候做切换工作即可。

Independent acquisition path:一个Time control unit一次只能控制一条Acquisition path 采集,如果想实现两个相机同时采集就必须用两个Time control unit,两条拥有不同的Time control unit的Acquisition path称为Independent acquisition path。如图彩色相机和单色相机的Acquisition path之间就是Independent acquisition path,可以同时采集。连接到两个Independent acquisition path上的Digtizer可以同时工作采图。

Data input channel (channel):经常我们会听到双通道采集,就是同一个Time control unit 的Capture源分为多个,每一个称为一个通道,在采集的时候可以切换采集,但是不能同时采集。

Device Number:MIL中分配Digtizer时要求指明每个Channel的第一条Acquisition path 的device number,MIL会根据相应的DCF文件自动计算总的Acquisition path数目,如指明channel 0的彩色相机的R Acquisition path为M_DEV0,那么G Acquisition path和

B Acquisition path相应就为M_DEV1和M_DEV2。这时候Channel 0的单色相机就只能分配从M_DEV3开始的Device Number了。如果板卡只有一个Time control unit,那么必须指明为M_DEV0或M_DEFAULT。

https://www.360docs.net/doc/5e8536409.html,采集和实时显示

MIL中采集有关函数都是以Mdig开头,开启采集操作的函数为MdigGrab,MdigGrabContinuous,MdigProcess,这三个函数的功能从字面上就很容易理解,分别对应单帧采集,连续采集和采集的同时处理。

在具体将这三个函数前,还要说明一点的就是要清楚三个Buffer之间的转移和大小及类型对应关系。这三个Buffer按数据传递顺序为相机Buffer、PC的Buffer(内存)、显存Buffer,示意图如下:

当我们采集的时候使用Mdig函数将数据从相机buffer传到PC的内存buffer(这里采用MIL 定义的Buffer)中,当我们显示的时候使用Mdisp函数将数据从内存buffer从传递到显存Buffer(这里指代显示的窗口)中。

这里注意示意图上的每一个小方格代表一个像素点数据,可以看到不是每个Buffer一开始就是大小不一定是一样的:如果相机Buffer大于PC Buffer采集的时候会自动将多的像素点截掉;如果相机Buffer小于PC Buffer采集的时候会自动从Buffer的初始点(默认为左上角)开始填充,PC Buffer中剩下未填充的会保持初始化状态(所以一般分配完Buffer后立即初始化);PC Buffer和显存Buffer的转移关系类似。如果相邻Buffer之间大小不一样,我们可以使用MdigControl控制采集时的比例(例如采集比例设为1/2,那么采集时从相机Buffer 间隔取值,相当于相机Buffer为原来的1/2),使用MdispZoom控制显示的比例(例如显示比例设为2,那么显示时从PC Buffer线性插补为原来2倍)。另外,如果想控制默认对齐的初始点,可采用MdigControl和MdispPan调整期对应参数,一般不改变,具体参看MIL 手册。为了获得采集的最佳效果,我们不应当对相机Buffer做任何假设,应该采用

MdigInquire函数来查询相机Buffer的大小和类型(例如8+M_UNSIGNED),分配对应的PC Buffer,同样不应当对显存Buffer做任何假设,应当查询显示Buffer大小,显示时对PC Buffer做相应放大缩小操作。

MdigGrab

示例代码如下

[cpp]view plaincopyprint?

1.//分配默认的应用、系统

2.MappAllocDefault(M_SETUP, &MilApplication, &MilSystem, M_NULL, M_NULL, M_NUL

L);

3.

4.//分配采集器

5.MdigAlloc(MilSystem, M_DEFAULT, "M_DEFAULT", M_DEFAULT, &MilDigitizer);

6.

7.int nGrabScaleSet = 4;//设置的采集比例

8.

9.//分配buffer

10.if (MsysInquire(MilSystem, M_SYSTEM_TYPE, M_NULL) == M_SYSTEM_HELIOS_TYPE)

11.{

12. BufferLocation = M_ON_BOARD;

13.}

14.MbufAlloc2d(MilSystem,

15.long(MdigInquire(MilDigitizer, M_SIZE_X, M_NULL) / nGrabScaleSet

),

16.long(MdigInquire(MilDigitizer, M_SIZE_Y, M_NULL) / nGrabScaleSet

),

17. MdigInquire(MilDigitizer, M_TYPE, M_NULL),

18. M_DISP + M_IMAGE + M_GRAB + BufferLocation,

19. &MilBufferImage);

20.MbufClear(MilBufferImage, 0xFF);

21.

22.//分配显示

23.MdispAlloc(MilSystem, M_DEFAULT, "M_DEFAULT", M_WINDOWED, &MilDisplay);

24.

25.//Buffer和Display绑定

26.MdispSelectWindow(MilDisplay, MilBufferImage, GetDlgItem(IDS_DISPLAY)->GetSa

feHwnd());

27.

28.//单帧采集两帧

29.MdigControl(MilDigitizer, M_GRAB_SCALE_X, 1.0/nGrabScaleSet);

30.MdigControl(MilDigitizer, M_GRAB_SCALE_Y, 1.0/nGrabScaleSet);

31.MdigControl(MilDigitizer, M_GRAB_MODE, M_ASYNCHRONOUS );

32.MdigGrab(MilDigitizer, MilBufferImage);

33.Sleep(1000);//停顿一秒

34.MdispZoom(MilDisplay, 2, 2);

35.MdigGrab(MilDigitizer, MilBufferImage);

36.Sleep(1000);//停顿一秒

37.

38.//释放资源

39.if (M_NULL != MilBufferImage)

40.{

41. MbufFree(MilBufferImage);

42.}

43.if (M_NULL != MilDisplay)

44.{

45. MdispFree(MilDisplay);

46.}

47.if (M_NULL != MilDigitizer)

48.{

49. MdigFree(MilDigitizer);

50.}

51.if (M_NULL != MilApplication)

52.{

53. MappFreeDefault(MilApplication, MilSystem, M_NULL, M_NULL, M_NULL);

54.}

MdigGrab很简单,就是每次从相机Buffer中抓取一帧到PC内存Buffer中,注意我们这里采用MdigInquire函数查询相机Buffer大小和分配,MdigControl控制采集比例,这里分配的PC Buffer和相机Buffer大小和类型是匹配的,但是这里的PC Buffer和显存Buffer(窗口大小)是不一样的,读者自己处理吧(GetWindowRect和MdispZoom)。

还需要注意的是采集的时候有两种基本模式,异步和同步,一般采集异步(M_ASYNCHRONOUS),具体含义请查看MIL手册。MdigGrabContinuous

开始连续采集

原则上我们推荐使用MdigProcess函数,首先可以使用多Buffer优化程序性能,其次给了我们对采集过程的强大控制能力,我们可以在采集回调函数中实时处理采集到的图像或保存采集的每一帧(这也是MIL录像功能实现的原理)。在示例中,我演示的是使用回调函数对采集到的每一帧添加一个序号。

程序注释我已经写的很清楚了,结合MIL手册相信写出完整的采集程序不是什么大问题了。

博客中完整代码文件下载链接

相关主题
相关文档
最新文档