一般来说我们讲到图像会关注它的分辨率,深度,格式,类型几个方面的参数,那么在MIL中新建一个图像要考虑哪些方面呢,换句话说,调用MIL函数新建图像时,要传入哪些参数呢?
数字化图像对应到计算机内存来说就是离散化的数字矩阵,在MIL中保存来说是C语言数组,数组的每一个值表明当前像素点的灰度值。MIL中并没有对应的图像新建函数,在MIL中将图像归类为一种Buffer(可以理解为就是一种C语言数组),我们主要通过调用Buffer新建函数的同时指明Buffer属性来新建图像。
1.MIL图像新建
在MIL中Buffer操作函数都以Mbuf开头,新建一个Buffer主要有三个函数MbufAlloc1d、MbufAlloc2d、MbufAllocColor,其中MbufAlloc1d、MbufAlloc2d分别新建单色一维和二维Buffer,MbufAllocColor主要针对新建彩色(Color)的图像Buffer(三维Buffer)。这里我们暂时不考虑MbufAllocColor。
在MIL中新建Buffer主要考虑一下几个方面
1.Buffer大小
对应到图像就是图像分辨率,如常见的800*600等
2.Buffer类型
包含Buffer深度和存储类型。Buffer深度即Buffer的每一个值在内存中用多少位表示,对应到图像即每个像素点的值在计算机中用多少位来表示,主要为1bit(二值图像),8bit(最常见灰度图像),16bit和32bit,同一个像素点用的位数越多,其图像越细腻;考虑到计算机存储的特点,可以指明每个点存储类型为M_FLOAT、M_SIGNED或M_UNSIGNED类型。
3.Buffer属性
最开始已经介绍过在MIL中通过调用Buffer新建函数的同时指明Buffer属性来新建图像,因为在MIL中很多地方需要用到类似的存储结构,所以它通过构建一个通用的存储结构再指明属性的方式来指明Buffer的用途,最基本的Buffer用途属性包括:存储简单的数据集合的数组属性M_ARRAY,存储图像的图像属性M_IMAGE,用于存储卷积模板的M_KERNEL,用于构建Look up tables的M_LUT(这个以后会考虑讲解),用于形态学操作模板的M_STRUCT_ELEMENT。对于图像属性还有一系列属性,稍后会讲解。
由于Buffer在计算机中内存中存储,在Buffer中同时提供了指明属性的方式来指明Buffer的存储位置。为什么要指明Buffer的存储位置呢,Matlab图像处理中就没有听说这个选项啊?这就是使用C/C++图像处理的优势啦,对图像处理做硬件级别的优化!首先,PC的内存分为虚拟内存和实际内存,这个用Windows的都知道,当电脑的实际内存不够使时,Windows会在硬盘上虚拟一块内存来当做实际内存来用,当然这个虚拟的内存性能是没办法跟实际内存相比的了,在MIL中安装MIL时会指明一块nonpaged内存这块内存就是MIL向主机PC申请的归MIL所有的实际内存,如果将Buffer分配到这块内存中那么它分配到的一定是实际内存,而将Buffer分配到其他主机内存是可能(内存不够用时才分配到虚拟内存中,一般还是分配到实际内存中)分配到虚拟内存中,对性能有较大影响,可以用MilConfig来配置这块实际内存大小;另外,现在PC配置的显卡都有自己的显存和处理器GPU,将图像数据保存在显存中用GPU做高速处理是现在常用的手段,当然前提是你的PC的显卡足够好;最后,Matrox公司不仅仅开发了MIL软件,还开发了和MIL配套使用的图像板卡,图像板卡有自己的内存和处理器,使用图像板卡可以采集图像、加快图像处理、使用硬件级别的图像处理算法等等,如果我们电脑上安装了MIL板卡,那么将要复杂的计算交给它来处理是不错的做法。最常用的几种属性为:Buffer保存在主机内存中M_HOST_MEMORY(默认),Buffer保存在MIL申请的实际内存中M_NON_PAGED和Buffer不保存在MIL申请的实际内存中M_PAGED,Buffer保存在显存M_VIDEO_MEMORY,Buffer保存在MIL板卡上M_ON_BOARD和Buffer不保存在MIL板卡上M_OFF_BOARD。其他优化选项一般不常用,请自行查阅手册。
下面我们再来专门说一说图像属性(M_IMAGE)的Buffer。
我们常说图像文件格式为JPG/JPEG、BMP、TIFF、PNG等等,我们考虑在一个文件中如何保存图像像素点数据,最简单的图像文件存储方式莫过于我们上面说的每一个像素点用一个值来描述他的灰度值,这就是常见的BMP格式图像文件存储方式,但是这样保存的图像文件太大,人们考虑对这些数据进行压缩存储,一个简单的图像文件内容结构示意图如下
文件头标明该图像是什么格式文件如JPG、BMP等,文件信息区标明该图像文件包含的图像大小等附加信息,文件数据区是实际像素点值的数据。当读入图像的时候,首先检查文件头得到当前文件格式,再查看相应的文件信息,最后按照每种格式图像指定的解析方式将文件数据区的数据读入内存为相应的像素点矩阵。这些图像文件存储格式的内部构成都是有国际标准的,所以各种不同的图像查看软件都可以打开这样的图像文件。
一般来说图像格式文件在内存中表现为像素点矩阵,但是同样这样占用的内存太大,当对内存限制比较厉害的时候,模仿图像文件文件的保存方式,我们也可以对图像数据在内存中的保存方式做同样的处理。所以我们可以猜想MIL中Buffer的存储方式为一个结构体,示意图如下:
这样处理以后,通过在指明Buffer属性为M_COMPRESS及相应的压缩方式M_JPEG_LOSSLESS 、M_JPEG2000_LOSSLESS 、M_JPEG_LOSSLESS_INTERLACED、 M_JPEG_LOSSY 、M_JPEG2000_LOSSY、M_JPEG_LOSSY_INTERLACED,将图像数据在内存中做相应的压缩存储,但是这样带来了一个副作用就是在内存中两个Buffer压缩方式不一样的时候相互转换或做处理要先将两个Buffer转换成同一种压缩格式,这样加大了计算量和计算时间,对性能带来了一定的影响。另外,还需要说明的是,这种内存中压缩存储方式各个软件处理方式都是不一样的,并没有一个统一的标准,我们想通过OPENCV来操作MIL对应的内存压缩图像数据基本上是不可能的,当然你得到了或破解了MIL的压缩方式是可以的。
图像属性的Buffer的基本用途是存储图像数据(M_IMAGE),除此之外我们可以给他附加另外的用途:采集(M_GRAB),显示(M_DISP),处理(M_PROCESS)。那么可能有人要问指明buffer是用作图像存储就够了,为什么还要指明附加用途呢?答案是指明 附加用途会针对特定用途做最优化处理,如选择最合适的压缩存储格式等等。这里就涉及到另外一个问题,如我建立Buffer指明M_GRAB属性,假设MIL做优化存储为JPG格式,这是针对采集做的优化,现在我对这个Buffer做滤波操作,假设滤波操作最好的BMP格式数据,这时候MIL内部就会做一个格式转换,同样这会损失一定性能,另一方面我们想用OPENCV操作MIL数据,这里我们通过 强制指定通用存储格式(M_DIB、M_DIRECTX、M_GDI)来达到抑制图像转换造成的性能消耗和不同图像处理包共用数据。2.图像显示
3.代码演示
最简单的新建和显示
MIL_ID MilApplication, /* Application identifier. */
MilSystem, /* System identifier. */
MilDisplay, /* Display identifier. */
MilImage; /* Image buffer identifier. */
//分配默认的应用,默认的sys是PC,默认的buffer有MIL安装时指定的默认DCF文件定义,
//默认的display和默认buffer关联,此时没有指明显示的windows窗体句柄用内建的窗口
//显示
MappAllocDefault(M_SETUP, &MilApplication, &MilSystem, &MilDisplay, M_NULL, &MilImage);
MessageBox(TEXT("取消显示"));
MdispSelect(MilDisplay, M_NULL);
/* 释放默认应用分配的资源. */
MappFreeDefault(MilApplication, MilSystem, MilDisplay, M_NULL, MilImage);
一般新建和显示流程
MIL_ID MilApplication, /* Application identifier. */
MilSystem, /* System identifier. */
MilDisplay, /* Display identifier. */
MilImage; /* Image buffer identifier. */
//1.分配默认的应用和系统
MappAllocDefault(M_SETUP, &MilApplication, &MilSystem, M_NULL, M_NULL, M_NULL);
//2.分配显示的图像Buffer
MbufAlloc2d(MilSystem, 500, 500, M_DEF_IMAGE_TYPE, M_IMAGE+M_DISP, &MilImage);
// 初始化Buffer,内存中绘制相应图像
MbufClear(MilImage, 0L);
MgraText(M_DEFAULT, MilImage, 0L, 0L, " MIL ");
//3.分配显示Display
MdispAlloc(MilSystem, M_DEFAULT, "M_DEFAULT", M_WINDOWED, &MilDisplay);
//4.图像Buffer内容显示到相应Display上,此后修改Buffer,Display自动刷新
MdispSelect(MilDisplay, MilImage);
// 取消显示
MessageBox(TEXT("取消显示"));
MdispSelect(MilDisplay, M_NULL);
//5.释放分配的资源.
MessageBox(TEXT("释放所有"));
MbufFree(MilImage);
MdispFree(MilDisplay);
MappFreeDefault(MilApplication, MilSystem, M_NULL, M_NULL, M_NULL);
显示到Windows窗体
MIL_ID MilApplication, /* Application identifier. */
MilSystem, /* System identifier. */
MilDisplay, /* Display identifier. */
MilImage; /* Image buffer identifier. */
//1.分配默认的应用和系统
MappAllocDefault(M_SETUP, &MilApplication, &MilSystem, M_NULL, M_NULL, M_NULL);
//2.分配显示的图像Buffer
MbufAlloc2d(MilSystem, 500, 500, M_DEF_IMAGE_TYPE, M_IMAGE+M_DISP, &MilImage);
// 初始化Buffer,内存中绘制相应图像
MbufClear(MilImage, 0L);
MgraText(M_DEFAULT, MilImage, 0L, 0L, " MIL ");
//3.分配显示Display
MdispAlloc(MilSystem, M_DEFAULT, "M_DEFAULT", M_WINDOWED, &MilDisplay);
//4.图像Buffer内容显示到相应Display上,此后修改Buffer,Display自动刷新
MdispSelectWindow(MilDisplay, MilImage, GetDlgItem(IDS_DISPALYAREA)->GetSafeHwnd());
// 取消显示
Sleep(5000);
MessageBox(TEXT("取消显示"));
MdispSelect(MilDisplay, M_NULL);
//5.释放分配的资源.
MessageBox(TEXT("释放所有"));
MbufFree(MilImage);
MdispFree(MilDisplay);
MappFreeDefault(MilApplication, MilSystem, M_NULL, M_NULL, M_NULL);