2.6. 缓存
如果某个实现对每个写操作支持范围、实现和可用状态的检查,通常会触发一系列对相机的读操作。大多数用于有效性检查的数值很少或不会发生变化,所以可以放入缓存。相机描述文件包含所有必需的定义以确保缓存的一致性。
图8 Area of Interest
为说明这一点,需要用到更复杂的例子。图8显示了相机图像上的AOI。相机只需要发送AOI内的图像,图中的AOI是由Top、Left、Width和Height四个参数给出的矩形。
图9 Controlling the Area of Interest
如图9所示,这四个参数都从寄存器中取出。当然,这种简单的方式不能很好地处理,因为这四个参数的取值范围都不是无限的。假定像素坐标从0开始,有下面的限制:
0 ≤ Left ≤ ImagerWidth −Width
0 ≤ Top ≤ ImagerHeight − Height
1 ≤ Width ≤ ImagerWidth − Left
1 ≤ Height ≤ ImagerHeight − Top
为了处理这些限制,每个参数的最大值都必须用SwissKnife节点计算;最小值是固定的。结果GenApi节点图如图10所示。注意,这里加入了第二层的Integer节点并且最大值由IntSwissKnife节点处理。
图10 Controlling the Area of Interest while taking restrictions into account
假定图像处理器有VGA模式(640 x 480),TopMax节点的XML代码看起来可能是这个样子的:
<IntSwissKnife Name="TopMax">
<pVariable Name="CURHEIGHT">HeightReg</pVariable>
<Formula>480-CURHEIGHT</Formula>
</IntSwissKnife>
让我们再回到缓存的话题,你应该不会希望每次设置Left属性的时候都去读一次HeightReg或者判断一次TopMax节点。这的确是不必要的,当(且仅当)你确定HeightReg只在GenApi自身写了一个新的值到这个寄存器的情况下才发生改变。这种情况下,你可以把HeightReg和TopMax的值放入缓存。
如果用户写了一个新的值到HeightReg,HeightReg缓存的值可以立即发生变化,并且需要令TopMax缓存无效。当下一次有人要访问Left节点的时候,会去读TopMax,因此为TopMax创建一个新的缓存入口。
规则:当一个节点的内容发生变化的时候,要通知其所有的客户端,以便客户端可以令缓存无效。
通常,相机描述文件中结点间的连接包含了所有需要的信息,以便实现程序能处理缓存而不需要用户操心。不过,在有些情况下,相对于节点直接描述的,相机本身包含更多的依存关系。
某些相机包含一个叫做Binning的属性,当Binning被置为ON,相邻像素的值(charge)被合并,实现较好的效果,但代价是分辨率较低。假设一个VGA分辨率的图像卡,典型的配置如下:
l 无Binning (640 x 480)
l 水平Binning (320 x 480)
l 垂直Binning (640 x 240)
l 全Binning (320 x 240)
在GenICam中,这个属性要用一个含有四个值的枚举型来描述(见图11)。改变binning就意味着改变图像卡尺寸——不是实际的物理图像卡,而是用来表示AOI参数的限制的逻辑图像卡尺寸。
图11 Controlling the Area of Interest taking binning into account
我们假定相机通过寄存器提供有关当前(逻辑)图像卡尺寸的信息。如图11所示,我们引入了两个新的节点:ImagerHeightReg和ImagerWidthReg。TopMax的XML代码看起来像这个样子:
<IntSwissKnife Name="TopMax">
<pVariable Name="CURHEIGHT">HeightReg</pVariable>
<pVariable Name="IMAGERHEIGHT">ImagerHeightReg</pVariable>
<Formula>IMAGERHEIGHT-CURHEIGHT</Formula>
</IntSwissKnife>
正如我们所见,如果用户改变Binning属性,ImagerHeightReg的值将会改变。然而这两个节点间没有数据流。为确保在BinningReg节点的内容变化的时候,ImagerHeightReg节点的缓存无效,必须在两个节点间引入一个<pInvalidator>连接。这个连接的唯一用途是,说明这两个属性间隐藏的依存关系,以及确保缓存总是一致的。
2.7. 识别并判断相机描述文件的版本
必须能够通过一种统一的方式,来识别一个相机描述文件,及其所描述的相机。另外,随着时间的推移,相机描述文件也要相应地扩展,例如,当相应的相机产品增加了属性的时候。这就产生了对版本机制的需求。GenApi语法本身也要与时俱进,例如,当加入了新的节点类型的时候,所以也要求对规范提供版本机制。
在<RegisterDescription>元素的属性列表中可以发现必要的方法,这个元素是XML文件最外层的框。下面来看一个例子:
<RegisterDescription
ModelName="Example01"
VendorName="Test"
ToolTip="Example 01 from the GenApi standard"
StandardNameSpace="None"
SchemaMajorVersion="1"
SchemaMinorVersion="0"
SchemaSubMinorVersion="1"
MajorVersion="1"
MinorVersion="0"
SubMinorVersion="0"
ProductGuid="1F3C6A72-7842-4edd-9130-E2E90A2058BA"
VersionGuid="7645D2A1-A41E-4ac6-B486-1531FB7BECE6"
xmlns="http://www.genicam.org/GenApi/Version_1_0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.genicam.org/GenApi/Version_1_0
../GenApiSchema_Version_1_0.xsd">
所描述的相机由VendorName: / ModelName 对来标识。因为有商标保护,我们可以假定VendorName是唯一的。ToolTip属性用来提供设备的附加信息,并且可以显示给用户,例如,用总线上设备的选择列表的方式。
相机描述文件内的名称可能来自不同的命名空间,关于这一点在第2.8.1章有更详细的说明。在一个给定的相机描述文件中,名称要么来自自定义的命名空间,要么来自标准命名空间。属性StandardNameSpace表示文件中所使用的标准命名空间。
一个相机描述文件中不同项目的版本信息遵循共通的规则,并使用一个由三部分组成的版本号(version number):
<Major>.<Minor>.<SubMinor>
例如,“1.4.2”
兼容性规则(compatibility rules)如下:
l Major版本号高的文件不向下兼容
l Minor版本号高的文件向下兼容
l 改变SubMinor仅仅表示修复了问题;总是应该使用SubMinor最高的文件
例:版本1.3.0兼容版本1.1.*,1.2.*和1.3.*(星号表示不关心)。它不兼容版本2.*.*。如果版本1.3.2可用,则应该用它来代替1.3.0。
2.7.1. 格式的版本
属性SchemaMajorVersion、SchemaMinorVersion和SchemaSubMinorVersion描述XML文件用的GenApi格式的版本。这些属性是强制的,目的是提供信息。另外,格式的Major和Minor版本号也反映在命名空间(参见xmlns入口)和格式的文件名(参见xsi:schemaLocation入口)。
在这个例子中,命名空间是“http://www.genicam.org/GenApi/Version_1_0”。需要用到这个格式文件的程序既可以根据URL通过互联网来得到它,也可以通过由schemaLocation的第二部分给出的路径来找到这个文件,这个路径是可选的,在这个例子中是“../../GenApi/GenApiSchema_Version_1_0.xsd”,并假定XML文件存放在GenICam参考实现的目录结构中。
xmlns:xsi入口的“http://www.w3.org/2001/XMLSchema-instance”描述了格式语言自身的命名空间。
注意,如果一个实现支持,例如版本1.3.*的格式,则必须提供3个格式文件:版本1.0.*、1.2.*和1.3.*,这是向下兼容的要求,因为旧的XML文件带有旧的命名空间,需要旧的格式文件;另一方面,这个实现不支持使用新版本格式文件的XML文件,例如1.4.*要被拒绝。因此,有必要把版本号反映到格式的命名空间。
2.7.2. 相机描述文件的版本
属性MajorVersion、MinorVersion和SubMinorVersion描述XML文件自身的版本。相机的制造商有责任遵守兼容性规则。
相机描述文件的向下兼容是什么意思呢。假设一个相机,其版本1.0仅仅实现了一个属性。现在假定这个相机为另一个属性扩展了firmware。有两个方法可以在相机描述文件中处理这个情况。如果仅仅把这个属性添加到XML文件,就是暗示这个属性已经存在了。因为对旧版的相机来说情况并非如此,所以新的文件不是向下兼容的,结果其版本号必须是2.0。
另一个更智能的解决办法是,在相机中(!)引入一个查询寄存器,用户可以检查这个寄存器以判断这个新的属性是否已经实现。现在可以加入这个新的属性,并允许用户通过属性的访问模式来判断属性是否实现。这样这个新的文件就是向下兼容的,其版本可以是1.1。当然,只有在一开始相机就提供这个查询机制的情况下,这个方法才是可行的。采用第二种方法的优点是,对于这个相机的整个家族,只需要维护一个相机描述文件。
注意,这里的兼容性(compatibility)指的仅仅是属性节点(feature nodes)及其功能,而不是实现节点(implementation nodes,参见2.8.2章以获得详细信息)。
2.7.3. 识别并缓存相机描述文件
加载一个相机描述文件可能包含一个或多个预处理步骤。为加快处理速度,预处理过的XML文件可以被放入缓存。在缓存中,需要一个key来唯一标识相机描述文件。把元素<RegisterDescription>的属性VendorName、ModelName、MajorVersion、MinorVersion和SubMinorVersion合并起来是足够了,但是用起来有点不方便。
为简化缓存,引入了VersionGuid属性,属性VersionGuid含有一个GUID,每当属性VendorName、ModelName、MajorVersion、MinorVersion或SubMinorVersion中任何一个发生变化的时候,都必须要改变这个GUID。VersionGuid唯一地标识一个相机描述文件的某个版本,和文件名。
不必把所有不同的相机描述文件都放入缓存,可以只放最新的文件,最新的文件通过向下兼容的方式包含了所有其它的。对于每个VendorName、ModelName和MajorVersion号,都有一个这样的文件。这种文件的缓存key是ProductGuid,ProductGuid也有一个GUID,每当VendorName、ModelName或MajorVersion发生改变的时候必须改变。