11.2 使用元组

HALCON 的一个优势是大多数算子都能自动处理多个输入值(元组值)。例如,您可以使用单个或多个输入区域调用算子 AreaCenter;算子会自动返回所有传递区域的面积和中心坐标。同样,如果您使用多个矩形坐标值调用 GenRectangle1,它会创建多个区域。

以下各节将提供有关以下方面的更多详细信息

11.2.1 使用单值或多值调用 HALCON 算子

您可以在参考手册中查看算子是否也适用于元组。例如,我们在下面展示了算子 AreaCenterGenRectangle1 的相关部分。

如您所见,像 HRegion 这样的图标类会自动处理多值;参数是否接受/返回多值并不能从签名中看到,只能在参数部分看到: 在这里,一个附加的 (-array) (在示例中: HRegion(-array)) 表示参数可以包含一个或多个值。

static void HOperatorSet.AreaCenter  
(HObject regions, out HTuple area, out HTuple row, out HTuple column)

HTuple HRegion.AreaCenter  
(out HTuple row, out HTuple column)

int HRegion.AreaCenter  
(out double row, out double column)

regions (input_object)region(-array) → HRegion
area (output_control)integer(-array) → HTuple (int / long)
row (output_control)point.y(-array) → HTuple (double)
column (output_control)point.x(-array) → HTuple (double)

static void HOperatorSet.GenRectangle1  
(out HObject rectangle, HTuple row1, HTuple column1, HTuple row2, HTuple column2)

public HRegion  
(HTuple row1, HTuple column1, HTuple row2, HTuple column2)

public HRegion  
(double row1, double column1, double row2, double column2)

void HRegion.GenRectangle1  
(HTuple row1, HTuple column1, HTuple row2, HTuple column2)

void HRegion.GenRectangle1  
(double row1, double column1, double row2, double column2)

rectangle (output_object)region(-array) → HRegion
row1 (input_control)rectangle.origin.y(-array) → HTuple (double / int / long)
column1 (input_control)rectangle.origin.x(-array) → HTuple (double / int / long)
row2 (input_control)rectangle.corner.y(-array) → HTuple (double / int / long)
column2 (input_control)rectangle.corner.x(-array) → HTuple (double / int / long)

相比之下,控制参数通过数据类型显示其包含单个或多个值: 前者使用基本数据类型,如 double,后者使用 HALCON/.NET HTuple 类。因此,您可以通过两种方式通过 HRegion 调用 GenRectangle1,一种是传递 doubles,另一种是传递 HTuple s(此处使用构造函数形式):

HRegion SingleRegion = new HRegion(10.0, 10.0, 50.0, 50.0);
HRegion MultipleRegions = new HRegion(new HTuple(20.0, 30.0), new HTuple(20.0, 30.0),
                                      new HTuple(60.0, 70.0), new HTuple(60.0, 70.0));

同样,可以通过两种方式调用 AreaCenter

double Area, Row, Column;
HTuple Areas, Rows, Columns;

Area = SingleRegion.AreaCenter(out Row, out Column);
Areas = MultipleRegions.AreaCenter(out Rows, out Columns);

下面,我们将提供有关图标元组("图标元组" 一节 )和控制元组("控制元组和 HTuple 类" 一节 )的更多信息。

11.2.2 图标元组

图标类 HImageHRegionHXLD 可以包含单个或多个对象。要处理元组中的所有元素,首先要使用算子 CountObj 查询元素的数量

int NumRegions = MultipleRegions.CountObj();

然后使用 HALCON 算子 SelectObj 或(使用 C# 时)算子 [] 访问元素

for (int i=1; i<=NumRegions; i++)
{
  HRegion Region = MultipleRegions[i];
  ...
}

请注意,在图标元组中  ! 元素索引以 1 开始.

您可以使用 HALCON 算子 ConcatObj 创建或扩展图标元组

HRegion ThreeRegions = SingleRegion.ConcatObj(MultipleRegions);

11.2.3 控制元组和 HTuple 类

对于控制元组,HALCON/.NET 提供了 HTuple 类。HTuple 实例可以包含 doubleintstringHHandle 类型的元素。它们还可以包含多种元素类型。

以下各节将介绍

11.2.3.1 访问元组元素

要处理一个元组的所有元素,首先要通过属性 Length 查询其长度:

int TupleLength = Areas.Length;

您可以使用算子 [] 访问元组元素:

for (int i=0; i<TupleLength; i++)
{
  double Element = Areas[i];
  ...
}

请注意,如果尝试读取一个不存在的元组元素,或者尝试将一个元素赋值给一个不同类型的变量而不进行类型转换,都会出现异常。

11.2.3.2 创建元组

HTuple 类提供了许多不同的构造函数(有关列表,请参见 Visual Studio 的对象浏览器)。下面一行创建了一个带有单一值的 int 元组:

HTuple Tuple1 = new HTuple(1);

相比之下,下面一行创建的是一个 double 元组:

HTuple Tuple2 = new HTuple(1.0);

您也可以向构造函数传递多个值。请注意,当混合使用 doubleint 值时(如下面一行),会创建一个 double 元组:

HTuple Tuple3 = new HTuple(1.0, 2);

相反,当值列表还包含 string 时,就会创建一个混合类型的元组,其中第二个值被存储为 int

HTuple Tuple4 = new HTuple(1.0, 2, "s");

元组或元组元素的类型可通过其属性 Type 查询:

HTupleType TupleType = Tuple4.Type;
HTupleType TupleElementType = Tuple4[1].Type;

通过在构造函数中传递元组,您可以非常简单地连接元组

HTuple Tuple5 = new HTuple(Tuple2, Tuple3);

您还可以通过写入一个不存在的元素,将元素追加到元组中:

Tuple3[2] = 3;

11.2.3.3 转换、歧义、意外结果

HTuple 类提供了许多隐式转换方法,因此您可以在大多数地方直观地使用基本数据类型。例如,这行

double Element = Areas[i];

会自动将元素(实际上是 HTupleElement 类的实例)转换为 double

同样,基本类型也会自动转换为 HTuple 实例。这种转换的缺点是,编译器通常无法判断你是想使用算子的简单版本还是元组版本,因此会出现相应的错误。例如,如果使用下面这一行,值既可以从 int 转换为 double,也可以转换为 HTuple

// HRegion SingleRegion = new HRegion(10, 10, 50, 50);

您可以通过在第一个参数后面加上 .0 来非常简单的解决歧义

HRegion SingleRegion = new HRegion(10.0, 10.0, 50.0, 50.0);

Matching 示例中,还有两个有歧义的例子,都是因为 basic-type 和 HTuple 参数混杂在同一个调用中。在第一种情况中,通过显式地将 double 参数转换为 HTuple 实例,解决了歧义问题:

private double    row, column;
HTuple            angleCheck;
HHomMat2D         matrix = new HHomMat2D();
matrix.VectorAngleToRigid(new HTuple(row), new HTuple(column), new HTuple(0.0),
      result.GetGenericShapeModelResult(0, "row"),
      result.GetGenericShapeModelResult(0, "column"),
      angleCheck);

在第二种情况下,HTuple 实例(只包含单个值)通过使用属性 D 显式地转换为 doubles,属性 D 将第一个元素的值返回为 double(实际上,这是 tuple[0].D 的快捷方式):

private double    rectPhi, rectLength1, rectLength2;
HTuple            rect1RowCheck, rect1ColCheck;
rectangle1.GenRectangle2(rect1RowCheck.D, rect1ColCheck.D,
  rectPhi + angleCheck.D,
  rectLength1, rectLength2);

通过类似的属性,您可以将元组元素转换成其他基本类型。但要注意的是,如果尝试将元素转换为 "错误" 类型,就会出现异常。

与输入参数不同,输出参数不会自动转换。有时,这会导致意外结果。例如,在下面的代码中,在调用 AreaCenter 时,输出参数和返回值都使用了 doubles :

HRegion MultipleRegions = new HRegion(new HTuple(20.0, 30.0), new HTuple(20.0, 30.0),
                                      new HTuple(60.0, 70.0), new HTuple(60.0, 70.0));
double Area, Row, Column;
HTuple Areas, Rows, Columns;

Area = MultipleRegions.AreaCenter(out Row, out Column);

因此,只会返回第一个区域的面积和中心点。如果将返回值赋值给 HTuple,但输出参数仍为 doubles ,也会发生同样的情况:

Areas = MultipleRegions.AreaCenter(out Row, out Column);

相反,如果您为输出参数传递 HTuple s 并将返回值赋值给 double,算子会返回所有区域的中心坐标,但只返回第一个区域的面积:

Area = MultipleRegions.AreaCenter(out Rows, out Columns);

11.2.3.4 用于处理元组的 HALCON 算子

HALCON 提供了许多用于处理元组的算子。在参考手册的 元组 一章中可以找到这些算子。HDevelop 用户向导 对这些算子进行了概述。请注意,这里使用的不是算子名称,而是相应 HDevelop 函数的名称,其中省略了 Tuple 并使用小写字母,例如,使用 rad 代替 TupleRad

11.2.3.5 算子过载

对于基本算术运算,HALCON/.NET 提供了算子重载。例如,算子 + 会自动调用 HALCON 算子 TupleAdd