转载自http://blog.csdn.net/wenzhou1219
前面讲到的都是离线的图像获取方法,实际中我们做机器视觉都是在线采集图像和处理,处理结果决定了计算机要给出的控制信号如电机运动等,这样就实现了实时视觉反馈运动。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。
2.MIL采集和实时显示
MdigGrab
- //分配默认的应用、系统
- MappAllocDefault(M_SETUP, &MilApplication, &MilSystem, M_NULL, M_NULL, M_NULL);
- //分配采集器
- MdigAlloc(MilSystem, M_DEFAULT, "M_DEFAULT", M_DEFAULT, &MilDigitizer);
- int nGrabScaleSet = 4;//设置的采集比例
- //分配buffer
- if (MsysInquire(MilSystem, M_SYSTEM_TYPE, M_NULL) == M_SYSTEM_HELIOS_TYPE)
- {
- BufferLocation = M_ON_BOARD;
- }
- MbufAlloc2d(MilSystem,
- long(MdigInquire(MilDigitizer, M_SIZE_X, M_NULL) / nGrabScaleSet),
- long(MdigInquire(MilDigitizer, M_SIZE_Y, M_NULL) / nGrabScaleSet),
- MdigInquire(MilDigitizer, M_TYPE, M_NULL),
- M_DISP + M_IMAGE + M_GRAB + BufferLocation,
- &MilBufferImage);
- MbufClear(MilBufferImage, 0xFF);
- //分配显示
- MdispAlloc(MilSystem, M_DEFAULT, "M_DEFAULT", M_WINDOWED, &MilDisplay);
- //Buffer和Display绑定
- MdispSelectWindow(MilDisplay, MilBufferImage, GetDlgItem(IDS_DISPLAY)->GetSafeHwnd());
- //单帧采集两帧
- MdigControl(MilDigitizer, M_GRAB_SCALE_X, 1.0/nGrabScaleSet);
- MdigControl(MilDigitizer, M_GRAB_SCALE_Y, 1.0/nGrabScaleSet);
- MdigControl(MilDigitizer, M_GRAB_MODE, M_ASYNCHRONOUS );
- MdigGrab(MilDigitizer, MilBufferImage);
- Sleep(1000);//停顿一秒
- MdispZoom(MilDisplay, 2, 2);
- MdigGrab(MilDigitizer, MilBufferImage);
- Sleep(1000);//停顿一秒
- //释放资源
- if (M_NULL != MilBufferImage)
- {
- MbufFree(MilBufferImage);
- }
- if (M_NULL != MilDisplay)
- {
- MdispFree(MilDisplay);
- }
- if (M_NULL != MilDigitizer)
- {
- MdigFree(MilDigitizer);
- }
- if (M_NULL != MilApplication)
- {
- MappFreeDefault(MilApplication, MilSystem, M_NULL, M_NULL, M_NULL);
- }
还需要注意的是采集的时候有两种基本模式,异步和同步,一般采集异步(M_ASYNCHRONOUS),具体含义请查看MIL手册。
MdigGrabContinuous
- //分配默认的应用、系统
- MappAllocDefault(M_SETUP, &MilApplication, &MilSystem, M_NULL, M_NULL, M_NULL);
- //分配采集器
- MdigAlloc(MilSystem, M_DEFAULT, "M_DEFAULT", M_DEFAULT, &MilDigitizer);
- int nGrabScaleSet = 4;//设置的采集比例
- //分配buffer
- if (MsysInquire(MilSystem, M_SYSTEM_TYPE, M_NULL) == M_SYSTEM_HELIOS_TYPE)
- {
- BufferLocation = M_ON_BOARD;
- }
- MbufAlloc2d(MilSystem,
- long(MdigInquire(MilDigitizer, M_SIZE_X, M_NULL) / nGrabScaleSet),
- long(MdigInquire(MilDigitizer, M_SIZE_Y, M_NULL) / nGrabScaleSet),
- MdigInquire(MilDigitizer, M_TYPE, M_NULL),
- M_DISP + M_IMAGE + M_GRAB + BufferLocation,
- &MilBufferImage);
- MbufClear(MilBufferImage, 0xFF);
- //分配显示
- MdispAlloc(MilSystem, M_DEFAULT, "M_DEFAULT", M_WINDOWED, &MilDisplay);
- //Buffer和Display绑定
- MdispSelectWindow(MilDisplay, MilBufferImage, GetDlgItem(IDS_DISPLAY)->GetSafeHwnd());
- //开始连续采集
- MdigGrabContinuous(MilDigitizer, MilBufferImage);
- MdigHalt(MilDigitizer);
- //释放资源
- if (M_NULL != MilBufferImage)
- {
- MbufFree(MilBufferImage);
- }
- if (M_NULL != MilDisplay)
- {
- MdispFree(MilDisplay);
- }
- if (M_NULL != MilDigitizer)
- {
- MdigFree(MilDigitizer);
- }
- if (M_NULL != MilApplication)
- {
- MappFreeDefault(MilApplication, MilSystem, M_NULL, M_NULL, M_NULL);
- }
MdigProcess
- // TODO: Add your control notification handler code here
- //分配默认的应用、系统
- MappAllocDefault(M_SETUP, &MilApplication, &MilSystem, M_NULL, M_NULL, M_NULL);
- //分配采集器
- MdigAlloc(MilSystem, M_DEFAULT, "M_DEFAULT", M_DEFAULT, &MilDigitizer);
- //分配显示buffer
- MbufAlloc2d(MilSystem,
- long(MdigInquire(MilDigitizer, M_SIZE_X, M_NULL)),
- long(MdigInquire(MilDigitizer, M_SIZE_Y, M_NULL)),
- MdigInquire(MilDigitizer, M_TYPE, M_NULL),
- M_DISP + M_IMAGE,
- &MilBufferImage);
- MbufClear(MilBufferImage, 0xFF);
- //分配显示
- MdispAlloc(MilSystem, M_DEFAULT, "M_DEFAULT", M_WINDOWED, &MilDisplay);
- //Buffer和Display绑定
- MdispSelectWindow(MilDisplay, MilBufferImage, GetDlgItem(IDS_DISPLAY)->GetSafeHwnd());
- /************************************************************************/
- /* 分配Buffer List */
- /************************************************************************/
- MappControl(M_ERROR, M_PRINT_DISABLE);
- //初始化buffer list
- for(m = 0; m < BUFFERING_SIZE_MAX; m++)
- {
- MilGrabBufferList[m] = M_NULL;
- }
- //分配尽可能多的buffer list
- if (MsysInquire(MilSystem, M_SYSTEM_TYPE, M_NULL) == M_SYSTEM_HELIOS_TYPE)
- {
- BufferLocation = M_ON_BOARD;
- }
- MilGrabBufferListSize=0;
- for(m = 0; m < BUFFERING_SIZE_MAX; m++)
- {
- //分配一个Buffer
- MbufAlloc2d(MilSystem,
- MdigInquire(MilDigitizer, M_SIZE_X, M_NULL),
- MdigInquire(MilDigitizer, M_SIZE_Y, M_NULL),
- MdigInquire(MilDigitizer, M_TYPE, M_NULL),
- M_IMAGE+M_GRAB+M_PROC+BufferLocation,
- &MilGrabBufferList[m]);
- if (MilGrabBufferList[m])//分配成功则初始化
- {
- MbufClear(MilGrabBufferList[m], 0xFF);
- LastAllocatedM = m;
- MilGrabBufferListSize++;
- }
- else//分配失败则停止分配
- {
- break;
- }
- }
- MappControl(M_ERROR, M_PRINT_ENABLE);
- //防止占完内存空间,释放最后一个buffer
- MbufFree(MilGrabBufferList[LastAllocatedM]);
- MilGrabBufferList[LastAllocatedM] = M_NULL;
- MilGrabBufferListSize--;//注意这里释放后一定要将相应的size-1,否则调用MdigProcess检测
- //到实际可用buffer size和传入的size参数不符,会报错
- /************************************************************************/
- /*采集和处理*/
- /************************************************************************/
- //设置待传递的数据
- UserHookData.MilImageDisp = MilBufferImage;
- UserHookData.ProcessedImageCount = 0;
- MdigProcess(MilDigitizer, MilGrabBufferList, MilGrabBufferListSize,
- M_START, M_DEFAULT, ProcessingFunction, &UserHookData);
- /************************************************************************/
- /*停止采集和处理*/
- /************************************************************************/
- MdigProcess(MilDigitizer, MilGrabBufferList, MilGrabBufferListSize,
- M_STOP, M_DEFAULT, ProcessingFunction, &UserHookData);
- //释放资源
- MappControl(M_ERROR, M_PRINT_DISABLE);
- for (m = 0; m < BUFFERING_SIZE_MAX; m++)
- {
- if(M_NULL != MilGrabBufferList[m])
- {
- MbufFree(MilGrabBufferList[m]);
- MilGrabBufferList[m] = M_NULL;
- }
- }
- if (M_NULL != MilBufferImage)
- {
- MbufFree(MilBufferImage);
- }
- if (M_NULL != MilDisplay)
- {
- MdispFree(MilDisplay);
- }
- if (M_NULL != MilDigitizer)
- {
- MdigFree(MilDigitizer);
- }
- MappControl(M_ERROR, M_PRINT_ENABLE);
- if (M_NULL != MilApplication)
- {
- MappFreeDefault(MilApplication, MilSystem, M_NULL, M_NULL, M_NULL);
- }
- long MFTYPE ProcessingFunction(long HookType, MIL_ID HookId, void MPTYPE *HookDataPtr)
- {
- HookDataStruct *UserHookDataPtr = (HookDataStruct *)HookDataPtr;
- MIL_ID ModifiedBufferId;
- char Text[10]= {'\0'};
- //得到buffer list获得采集数据的buffer号
- MdigGetHookInfo(HookId, M_MODIFIED_BUFFER+M_BUFFER_ID, &ModifiedBufferId);
- UserHookDataPtr->ProcessedImageCount++;
- //当前图片上写入采集编号
- MOs_ltoa(UserHookDataPtr->ProcessedImageCount, Text, 10);
- MgraText(M_DEFAULT, ModifiedBufferId, 10, 10, Text);
- //处理完的Buffer数据复制到显示buffer
- MbufCopy(ModifiedBufferId, UserHookDataPtr->MilImageDisp);
- return 0;
- }