机器视觉_HALCON_HDevelop用户指南_4.HDevelop开发程序

news2024/11/20 0:36:18

文章目录

  • 四、HDevelop编程
    • 4.1. 新建一个新程序
    • 4.2. 输入一个算子
    • 4.3. 指定参数
    • 4.4. 获取帮助
    • 4.5. 添加其他程序
    • 4.6. 理解图像显示
    • 4.7. 检查变量
    • 4.8. 利用灰度直方图改进阈值
    • 4.9. 编辑代码行
    • 4.10. 重新执行程序
    • 4.11. 保存程序
    • 4.12. 选择特征区域
    • 4.13. 打开图形窗口
    • 4.14. 循环遍历结果
    • 4.15. 总结


四、HDevelop编程

本章节介绍如何用HDevelop来开发你自己的机器视觉应用程序。这意味着,这些内容在实际开发中要积极遵循。接下来,假设HDevelop的属性都为默认值,即整个IDE处于一个默认状态(一般在新安装后,HALCON是处于默认状态的)。如果你不确定当前配置是否是默认状态,你可以调用以下命令行来启动HDevelop,以使用默认设置。

hdevelop -reset_preferences

本章节会处理一个简单例子。给定下列图片,目标是统计回形针的数量并确定它们的方向。
在这里插入图片描述

4.1. 新建一个新程序

打开HDevelop,单击 文件>新程序(New Program,翻译成新建程序好些;中文版HDevelop的翻译比较死) 来新建一个程序。若当前程序有未保存的更改,HDevelop会通知你。如果你重新排列过窗口,单击 窗口>排列窗口 可以恢复至默认布局(而且是适应窗口大小的) 。

第一件要做的事是读取图像并将其存储在一个图像变量(iconic variable)中。从上一章节可知,我们可以轻松拖动一个图像到HDevelop窗口中,这将插入 read_image 算子至程序中。

4.2. 输入一个算子

单击算子窗口的文本框,输入 read_image 并按下回车键(Enter,macOS中是Return键)。你也可以输入算子名称的子串(比如read_image,输入read_i)并按下回车键(其实就是字符串匹配)。HDevelop将打开匹配输入字串的算子列表。用这种方式,你可以轻松地选择算子,而无需输入算子的确切名称(全名)。接着用鼠标或方向键标记所需的算子,然后按下回车键确认选择。若你不小心选错了算子,可以单击算子名称边上的下拉箭头重新打开列表。
在这里插入图片描述

4.3. 指定参数

在选中一个算子后,它的参数会显示在算子窗口中。参数会按图像和控制参数分组。参数名称边上的图标表示参数类型:输入 与 输出。语义类型显示在参数的右侧。参数在文本域中指定。首个参数会获取到输入焦点。
在这里插入图片描述

Image 文本域中输入 Clip ,图像会存储到该变量中。接着在 FileName 文本域输入 ‘clip’ (按Tab可以跳转到下一个输入域,按下Shift+Tab可以返回上一个输入域,用这种方式不用鼠标就能输入所有参数)。

点击 确定 将算子添加到当前程序中 并执行 (强调一下,确定按钮是有执行效果的)。接着,将执行以下操作:

  • 算子调用会被添加至当前程序的第一行。
  • IC会前进一行,因为在该行插入后,后面可能将插入新的行。
  • 字符 * 添加到了窗口标题中
    在这里插入图片描述
    ,以指示当前程序中存在未保存的更改。在程序窗口中的当前程序(main)也会被 * 标记。
  • 程序行被执行,且PC前进。更准确地说:从PC到IC的所有行都被执行。
  • 图像显示在图形窗口中。
  • 状态栏更新,即 read_image 的执行时间会被显示,加载图像的格式会被报告。
  • 输出变量 Clip 会被创建并显示在变量窗口中。
  • 算子窗口被清除,并为插入下一个算子做准备。

小结
这小节可能说了一堆也不知道是什么,其实就是图形化配置算子的调用。
先选择目标算子,然后配置算子的输入输出参数,点击确定就会生成代码插入到程序中执行。执行完,图像输出到输出变量中,供后续使用。

4.4. 获取帮助

你也许会好奇 clip 图像是从哪里加载的,因为我们没有指定任何路径,甚至是文件扩展名(这里指上小节的FileName文本域中,我们仅输入一个’clip’就成功加载图片了)。这与HALCON算子 read_image 工作方式的一个细节有关。HDevelop对此一无所知,它只是执行带有你提供的参数的算子罢了。

在HDevelop内,访问算子说明文档非常容易。
双击程序窗口的第一行代码,该算子的信息会显示在算子窗口中,可供编辑。现在点击 帮助(算子窗口中的) 打开HDevelop在线帮助窗口。它将自动跳转到所显示算子的文档。参考手册是完全交叉链接的(cross-linked,交叉链接大概是说可以互相跳转)。窗口左侧的导航提供了对文档的快速访问。目录 选项卡显示了文档的层次结构。
在这里插入图片描述
算子 选项卡列出了所有可直接访问的算子。在 查找 文本框输入字串,以快速查找匹配的算子。

在本章节的剩余部分,尽可能地使用帮助文档来获取算子的信息。

4.5. 添加其他程序

通过阈值化来选出回形针

现在,我们要从图像中分离出回形针。首先,用肉眼可以看出来,回形针很明显与背景不同,因此基于灰度值(gray value)做选取比较合适,该操作被称为 阈值化(thresholding) (常说的二值化,其实就是阈值化的一个特例;很多场景下两者也可以等同起来)。

在算子窗口中输入 threshold ,这既是一个算子的全名,也是某些算子名称的一部分。因此,当你按下回车键,将会得到一个匹配了字符 threshold 的算子列表。再次按下回车键确认所选算子并显示其参数。
在这里插入图片描述
可以看到,上图中输入参数 Image 被自动设为 Clip 。因为没有默认值的输入变量,HDevelop会收集之前相同类型的输入变量,自动推断出合理的建议值。因此,最近的相匹配的输出参数的名称会出现在这(最近指的是当前程序行前面的)。在本例中,只有 Clip 可用。

MinGrayMaxGray 分别设为 0 和 30 。这将选中图像中的深色像素。

点击 应用 ,该按钮会执行算子但不会将其添加到程序中。此外,它会保持当前参数窗口打开可编辑的状态。这样,你就能很容易地尝试不同的设置值,并立即查看结果。所选像素(即所谓的 region )会存储在输出变量 Region 中,并显示在变量窗口中。该 region 是一个图像掩码(mask):白色像素会被选中,而黑色像素不会。
在这里插入图片描述

该区域还会在图形窗口中显示为覆盖层。所选像素显示为红色(可以更改默认设置,使其变为其他颜色)。

所选的阈值并不完美,稍后我们会对此进行更正。现在,单击 输入 将算子添加到程序窗口。与单击 确定 的效果不同,这并不会执行算子。注意,变量 Region 会保持其值,但不再显示在图形窗口中。而且,PC也没有前进,说明程序的第二行并未执行。

如果某些输入参数使用的变量名会在以后添加到程序中,那么使用 输入 添加程序行会很有用。

后继函数(Successor)

本小节中,一会儿是后继函数,一会儿是后继算子。我觉得两者应该是等价的,只是HDevelop中文版翻译的问题,不必纠结。

点击刚插入的程序行以选中它,可以让HDevelop根据所选行推荐算子。打开菜单 建议>后继函数 。该菜单是动态填充的,会显示当前算子的常用后继算子。现在,我们把选中的像素分割成连续的区域。鼠标指针移到菜单项上,状态栏会显示所标注算子的简短说明。查看菜单项,单击 connection 算子项。通过该菜单选择的任何算子都会转移到算子窗口中。

同样,HDevelop建议的变量名看起来也很合理,因此点击 确定 。这次,执行了两行程序:阈值操作(threshold)和连接操作(connection)。该结果也如前文所述,单击 确定 会从PC执行到IC。

在图形窗口中,由 connection 算子计算的连续区域现在以交替的颜色显示(交替就是说相邻不同色)。
在这里插入图片描述

4.6. 理解图像显示

本小节中的区域指的是region类型的图像变量。和XLD、image一样都是图像数据类型(iconic data)。

在执行了程序的三行代码之后,图形窗口实际上显示了三层图像变量:

  • image Clip,回形针图像
  • region Region
  • region元组(tuple of regions), ConnectedRegions (从上到下)。

(这里的image和region是图像变量的类型)
将鼠标悬停在变量窗口的图像变量上,可查看变量的基本信息。
在这里插入图片描述

在图形窗口的上下文菜单(鼠标右键出现的菜单)中可以调整图像和最上层 region 的显示属性。对于图像(images),可以设置查找表(look-up table,缩写为LUT)和显示模式(称作Paint,显示)。LUT指定灰度值映射。尝试不同设置:在图形窗口中右击,从Lut和Paint菜单中选择一些值。确保菜单中的项 立刻应用变化(Apply Changes Immediately) 是选中的。注意观察图的显示如何变化,而region保持不变。

菜单项 彩色(Colored)、颜色(Color)、画/绘图方式(Draw)、线宽(Line Width)和形状(Shape) 会更改最顶部region的显示属性。将 画/绘图方式 设为 margin(边缘)颜色 设为 cyan(青色)形状 设为 eclipse(椭圆)ConnectedRegion (最顶层) 的显示也随之改变。而区域 Region 仍然以红色填充显示。

一种更便捷的方法是通过上下文菜单中的 设置参数 来一次设置多个显示属性。单击该项,会打开如下的设置窗口。
在这里插入图片描述
尝试一些设置后,单击 重置 按钮可以恢复默认可视化设置。

无法更改最顶层以外的区域(或XLD)的显示属性。你可以在图形窗口中通过双击变量窗口中的图像变量手动重建图像堆栈,并在每次添加一层时更改属性。每当添加使用全域(full domain)的图像时,堆栈会被清除。要手动清除堆栈(以及图形窗口),单击 清空图形窗口 图标。

4.7. 检查变量

将鼠标指针移到变量 ConnectedRegions 上时,你会看到它包含98个区域(regions)。

右键单击图像变量 ConnectedRegions 并选中 清除/显示 ,以在图形窗口中只显示连接的区域。再次右键单击,选中 显示目录>选择… 。该菜单项会打开一个变量检查窗口,其中列出了变量 ConnectedRegions 的内容。该检查窗口的选定区域将使用当前可视化设置显示在图形窗口中。将 画/绘图方式 设为 边缘形状 设为 椭圆 ,并从列表中选中一些区域。效果如下:
在这里插入图片描述
现在,暂时关闭变量检查窗口。产生了如此大量的区域是由于 threshold 算子的边界设置过于粗糙。下面将使用HDevelop的可视化工具来交互式地找到更合适的设置。

4.8. 利用灰度直方图改进阈值

点击 可视化/工具 => 灰度直方图 ,打开灰度直方图检查工具。它的用途之一是直观地确定阈值边界。由于图形窗口当前仅显示区域(未显示背景),因此灰度直方图为空。双击变量窗口中的 Clip 图像变量,以重新显示原始图形,并观察其灰度直方图。

展开直方图窗口下方 范围选筛选及代码生成 项。在其操作列中选中 阈值 ,单击 阈值 左侧的图标以使操作可视化。现在,你可以通过更改 最小化(Min)最大化(Max) 中的值或拖动直方图区域中的竖线来尝试不同的阈值边界。对这些值的任何更改都会立即显示在活动的图形窗口中。0和56分别适用于下界和上界。
在这里插入图片描述

4.9. 编辑代码行

要在算子窗口中编辑代码行,需要在程序窗口中双击该行。在算子窗口中对参数进行更改并单击 确定替换 ,程序中的代码行会被更新。当然,你也可以直接在程序窗口中编辑程序。

双击上述程序的第二行调整阈值操作。将 MaxGray 的30替换为56,单击 替换 。程序窗口中的程序行被更新。

4.10. 重新执行程序

最后一步编辑程序,只是进行了微小的修改。通常,在编辑了程序中的许多行并对变量进行了多次更改后,你会希望将程序重置到初始状态并再次运行以查看更改后的整体效果。

点击 执行>重置程序执行 来重置程序。现在,选中 执行>运行 来运行完整的程序,或 重复点击 执行>单步跳过函数 来一行行执行程序。

4.11. 保存程序

现在是保存程序的好时机。选中 文件>保存 并为你的程序指定目标目录和文件名。

4.12. 选择特征区域

在修改阈值操作之后,检查变量 ConnectedRegions ,产生了更好的结果。但是,图像左侧边缘的一个连续区域仍然被返回了,如下图。
在这里插入图片描述

为了只获取与回形针重合的区域,需要一个标准进一步减少目前的区域。与灰度直方图类似,HDevelop提供了特征直方图工具,它能帮你根据区域的共同属性或特征选出特征区域。

点击 可视化/工具 > 特征直方图 来打开该工具。展开窗口下方的 特征选择与代码生成 项。 特征 列允许区域选择将基于的特征。默认特征是 area(面积) ,在本例中这就足够了:实际的回形针大小几乎相同,因此区域的面积是一个共同特征。在特征直方图中,横轴对应所选特征的值。纵轴对应某特征出现的频次。

与灰度直方图窗口类似,你可以可视化所选区域,即面积大小在 最小值 和 最大值之间的区域,分别由绿色和红色竖线表示。单击所选特征左侧的图标,启用可视化。
在这里插入图片描述

在特征直方图窗口的 输入和输出 段指定参数。拖动绿色和红色线,观察这会如何影响选中的区域。在直方图中,我们可以看到,为了覆盖所有的回形针,我们可以选择面积介于4000和直方图最大值之间的区域。当你对所选内容满意时,单击 插入代码 按钮。下面这行代码(具有类似数值)将添加至程序中IC的位置:

select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 4000, 6703.77)

运行程序,并检查输出变量 SelectedRegions 。与回形针对应的区域现在能被正确识别了。要获取回形针的方向和重心(center of gravity),将以下算子调用添加到程序中:

orientation_region (SelectedRegions, Phi)
area_center (SelectedRegions, Area, Row, Column)

算子 orientation_region 会返回一个元组值:SelectedRegions 中的每个区域,在 Phi 中都有对应的方位值返回。算子 area_center 以同样的方式将每个输入区域的 Area(面积)、Row、Column 作为元组返回。再次运行程序并检查计算出的控制变量。你能在一个检查窗口中检查多个控制变量。若控制变量都是相互关联的,如本例,这会很有用。在变量窗口中选择所有控制变量(按住Ctrl),然后右键单击 监视/查看(Inspect)
在这里插入图片描述

4.13. 打开图形窗口

到目前为止,图像数据的可视化依赖于这样一个事实:HDevelop启动时,图形窗口始终默认打开。而在程序中显式地打开不同数量的图形窗口是一种比较好的做法。

在程序的第一行前面添加以下代码:

dev_close_window ()
dev_open_window (0, 0, 512, 512, 'black', WindowHandle)

第一行关闭所有打开的图形窗口,以确保程序开始时的状态一致。第二行打开一个图形窗口,该窗口可以通过输出变量 WindowHandle 引用。窗口句柄是一个神奇的值,它也显示在相应图形窗口的标题栏中。

4.14. 循环遍历结果

作为一个集成开发环境,HDevelop还提供了其他编程语言的特性:变量赋值、表达式和控制流。变量赋值和控制流是以特定的HDevelop算子实现的,这些算子可以从菜单 算子>控制 中选择。表达式是根据特定的HDevelop语言实现的,可用于算子调用的输入控制参数。

要遍历 Phi 中的元素,我们使用一个 for 循环,从0(元组第一个元素的下标)开始计数到元素个数减1。 for 循环的输入就像一个普通的HALCON算子:在算子窗口中输入 for 并指定其参数,如下图。
在这里插入图片描述
注意,若选中右侧的复选框(checkbox),则会自动输入 endfor 。还要注意的是,IC会被放置在添加的行之间,以便可以直接往循环体添加程序。
在这里插入图片描述
符号 |Phi| - 1 是HDevelop语言的一部分。该运算计算的是Phi元素的个数减1。当插入到程序窗口中时, for 算子会以不同的格式显示,以增强可读性。

将以下指令添加到程序中。它在程序窗口中会自动缩进,以突出显示 for 循环中的嵌套。第一行末尾处的反斜杠允许程序行在下一行继续,以提高可读性(C语言中也有,相当于避免单行程序过长,而在显示上分成多行)。

dev_disp_text (deg(Phi[Index]) + ' degrees', 'image', Row[Index], \
                 Column[Index], 'black', [], [])

dev_disp_text 算子提供了一种便捷的方法,以在活动的图形窗口中的特定位置输出文本。按 F1 可获取相关参数含义的更多信息(选中程序行的算子,按下F1会跳转到说明文档)。符号 Phi[Index] 是HDevelop语言的另一种操作。它提供了对元组中单个值的访问(有点像数组了)。函数 deg 将参数从弧度转化为角度。本例中,+ 用于字符串连接,参数 'degrees’是一个字符串值。在连接 + 的两个操作数之前,会自动进行数值参数的类型转换(double类型转字符串类型)。其中细节在 HDevelop语言 章节中有解释。

注意,选择围绕 dev_disp_text 的循环是为了说明如何访问元组的单个元素。在该例中,实际上并不需要循环,因为 dev_disp_text 足够智能,可以直接操作元组。可以用以下调用来代替循环:

dev_disp_text (deg(Phi) + ' degrees', 'image', Row, Column, 'black', [], [])

4.15. 总结

这是一个在HDevelop中创建程序的基本方式。选择一个算子,指定它的参数,使用 应用 按钮尝试不同的设置值,使用 输入确定 添加新的程序行,然后在程序窗口中双击进行编辑。开发过程中,使用HDevelop提供的交互式工具来辅助开发,如,为算子找到合适的阈值。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/191444.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Swig工具在win10上使用

SWIG 是一种软件开发工具,它将 C 和 C 编写的程序与各种高级编程语言连接起来。这里我们用它来将 C/C 转换成 Java。 一、Swig安装 1、下载 官网:SWIG官网下载 源码链接 GitHub:https://github.com/swig/swig.git 这两个地址可能会出现无…

STM32单片机智能蓝牙APP加油站火灾预警安防防控报警监控系统MQ2DHT11

实践制作DIY- GC0122-智能蓝牙APP加油站火灾预警 一、功能说明: 基于STM32单片机设计-智能蓝牙APP加油站火灾预警 功能介绍: 基于STM32F103C系列最小系统,MQ-2烟雾传感器,火焰传感器(不能直视阳光会受到阳光干扰&…

Cesium 渐变长方体实现-Shader

position获取: 1.1 在cesium中,可通过vec4 p = czm_computePosition();获取 模型坐标中相对于眼睛的位置矩阵 1.2 vec4 eyePosition = czm_modelViewRelativeToEye * p; // position in eye coordinates 获取eyePosition 1.3 v_positionEC = czm_inverseModelView * eyePo…

Python流程控制详解

和其它编程语言一样,Python流程控制可分为 3 大结构:顺序结构、选择(分支)结构和循环结构。 Python对缩进的要求(重点) Python 是一门非常独特的编程语言,它通过缩进来识别代码块,…

ConditionalOnBean详解及ConditionalOn××总结

ConditionalOnBean详解 为什么学习ConditionalOnBean 在学习 Springboot 自动装配的时候遇到 Bean 装配和 Bean 配置需要条件判断的场景时,查阅了相关内容了解到 Conditional 和 ConditionalOnBean 注解,深入学习之后受益匪浅。 ConditionalOnBean测试…

后量子 KEM 方案:Newhope

参考文献: Lyubashevsky V, Peikert C, Regev O. On ideal lattices and learning with errors over rings[J]. Journal of the ACM (JACM), 2013, 60(6): 1-35.Lyubashevsky V, Peikert C, Regev O. A toolkit for ring-LWE cryptography[C]//Advances in Cryptol…

Linux常见指令大全(一)

🌹作者:云小逸 📝个人主页:云小逸的主页 📝Github:云小逸的Github 🤟motto:要敢于一个人默默的面对自己,强大自己才是核心。不要等到什么都没有了,才下定决心去做。种一颗树,最好的时间是十年前…

POE交换机全方位解读(上)

POE交换机在安防行业的应用,给视频监控系统带来了质的改变,POE交换机。可通过网线为无线AP、网路摄像头等PoE终端设备供电,传送距离可达100m,安装简单,即插即用。非常适合无线城市、安防监控等行业使用。 POE供电方案及…

「融云政企数智办公解决方案」入选「大信创产品目录」

1月31日,CIO 时代、新基建创新研究院联合公布“大信创产品目录”,“融云政企数智办公解决方案”成功通过审核,被正式纳入“大信创产品目录”。 据悉,CIO 时代、新基建创新研究院从去年底开始组织开展“大信创产品目录”征集工作&a…

【C语言 数据结构】数组与对称矩阵的压缩存储

文章目录数组的定义数组的顺序表示和实现顺序表中查找和修改数组元素矩阵的压缩存储特殊矩阵稀疏矩阵数组的定义 提到数组,大家首先会想到的是:很多编程语言中都提供有数组这种数据类型,比如 C/C、Java、Go、C# 等。但本节我要讲解的不是作为…

frp构建多级网络代理

简介frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP、UDP、HTTP、HTTPS 等多种协议,采用 Golang 编写,支持跨平台,仅需下载对应平台的二进制文件即可执行,没有额外依赖。frp可以将内网服务以安全、便捷的方…

Idea 中【Maven】的环境配置

目录 一 maven 项目管理工具软件二.首先要安装Jdk1.7/8 和IDEA三.在IDEA中配置maven四.在MavenDemo01下 创建多个模块项目四.Jar包依赖 插件五.运用一 maven 项目管理工具软件 1 . Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的项目管理工具…

MQ如何保证消息不丢失

如何保证消息不丢失 哪些环节会造成消息丢失 其实主要就是跨网络的环境中需要考虑消息的丢失,主要是有以下几个方面 生产者往MQ发送消息MQ的Broker是集群有主从的,主节点把消息同步到从节点时也需要考虑消息丢失问题消息从内存持久化到硬盘时&#xf…

软考高级系统架构师背诵要点---软件架构设计

软件架构设计 软件架构的概念: 软件架构为软件系统提供了一个结构、行为和属性的高级抽象,由构成系统的元素的描述、这些元素的相互作用、指导元素集成的模式及这些模式的约束组成 软件架构41视图: 逻辑视图:主要是整个系统的抽…

Java基础:面向对象

一、设计对象并使用 二、封装 对象代表什么,就得封装对应的数据,并提供数据对应的行为。 1.private关键字:priviate修饰的成员变量只能在本类中访问。 2.this关键字:能够直接对应成员变量(当局部变量名相同时)。 3. 构造方法…

【Linux】十分钟快速了解Linux常用指令(建议收藏)

目录💖一. 关机指令01. shutdown02. halt03. reboot💖二. 常用指令04. ls05. pwd06. cd07. touch08. mkdir09. rm10. man11. cp(复制)12. mv指令13. nano14. cat15. less16. head17. tail18. find19. grep20. zip/unzip21. tar💖三、 日期指令…

JS 中 reduce()方法及使用详解

reduce()方法可以搞定的东西特别多,就是循环遍历能做的,reduce都可以做,比如数组求和、数组求积、统计数组中元素出现的次数、数组去重等等。 reduce() 方法对数组中的每个元素执行一个由您提供的reduce函数(依次执行),将其结果汇…

Python字符串分割方法【心得总结】

Python中字符串分割的常用方法 是直接调用字符串的str.split方法, 但是其只能指定一种分隔符, 如果想指定多个分隔符拆分字符串需要用到re.split方法 (正则表达式的split方法) 源码资料电子书:点击此处跳转文末名片获取 str.spli…

OAuth2简单介绍

目录 一、什么是OAuth2 二、OAuth2中的角色 1、资源所有者 2、资源服务器 3、客户 4、授权服务器 三、认证流程 四、生活中的OAuth2思维 五、令牌的特点 六、OAuth2授权方式 1、授权码 2、隐藏式 3、密码式 4、凭证式 一、什么是OAuth2 OAuth2.0是目前使用非常广…

7个高频出现的面试题

收集了2022年所有学生的面试题后,我整理出了7个高频出现的面试题,一起来看看。 高频问题1:请自我介绍下? 高频问题2:请介绍下最近做过的项目? 高频问题3:请介绍下你印象深刻的bug? 高…