虽然您可以拥有 HDevEngine/Python 的多个 Python 实例,但它们都共享相同的可变单例实现。
这主要影响配置。具体的程序和函数调用实例或多或少是相互独立的。
在这里,HALCON 会查询示例目录路径,并据此构建包含 "detect_fin" 函数的路径。然后初始化一个 HDevEngine 实例,并将函数搜索路径设置为该实例。
example_dir = ha.get_system_s('example_dir') procedure_path = os.path.join(example_dir, 'hdevengine', 'procedures') hdev_engine = ha.HDevEngine() hdev_engine.set_procedure_path(procedure_path)
def set_attribute(self, name: str, value: HTupleType) -> None: def get_attribute(self, name: str) -> HTupleType:
通过这些函数可以设置特定属性。例如,默认情况下,"ignore_invalid_results" 属性设置为 true。这意味着,如果查询的变量或参数不是程序或函数先前设置的,则默认情况下会返回空区域对象或空元组。试想一下:访问一个未初始化的变量是返回默认值还是引发异常?
hdev_engine = ha.HDevEngine() assert hdev_engine.get_attribute('ignore_invalid_results') == 1 hdev_engine.set_attribute('ignore_invalid_results', 0) assert hdev_engine.get_attribute('ignore_invalid_results') == 0
对于 HDevEngine 属性,0 表示 false,1 表示 true。
有关可用属性的列表,参见 "类概述" 一节 。
HDevEngine def start_debug_server(self) -> None: def stop_debug_server(self) -> None:
通过这些函数,可以启动和停止调试引擎执行所需的服务器。您可以通过属性 "debug_port" 控制端口。
HDevEngine def set_procedure_path(self, path: str) -> None: def add_procedure_path(self, path: str) -> None:
通过这些函数,您可以设置和扩展在尝试加载函数时搜索的路径列表。
HDevEngine def get_procedure_names(self) -> List[str]: def get_loaded_procedure_names(self) -> List[str]: def get_global_control_var_names(self) -> List[str]: def get_global_iconic_var_dimension(self, name: str) -> int: def get_global_control_var_dimension(self, name: str) -> int:
通过这些函数可以查询全局元数据,例如加载了哪些函数、全局变量的向量维数等。
HDevEngine def set_global_iconic_var(self, name: str, value: HObject) -> None: def set_global_iconic_vector_var(self, name: str, value: IconicVectorType) -> None: def set_global_control_var(self, name: str, value: HTupleType) -> None: def set_global_tuple_vector_var(self, name: str, value: TupleVectorType) -> None: def get_global_iconic_var(self , name: str) -> HObject: def get_global_iconic_vector_var(self, name: str) -> TupleVectorType: def get_global_control_var(self, name: str) -> HTupleType: def get_global_tuple_vector_var(self, name: str) -> TupleVectorType:
通过这些函数可以读写全局变量,包括图标变量和控制变量。
从 Python 调用 HDevelop 函数的一般概念如下:
procedure = ha.HDevProcedure.load_external('detect_fin') proc_call = ha.HDevProcedureCall(procedure) proc_call.set_input_iconic_param_by_name('Image', img) proc_call.execute() fin_area = proc_call.get_output_control_param_by_name('FinArea')[0] print(f'Fin Area: {fin_area}')
HDevProcedure @staticmethod def load_external(name: str) -> 'HDevProcedure': @staticmethod def load_local( program: Union[HDevProgram, str], name: str ) -> 'HDevProcedure':
函数通过这些静态方法加载。只能使用这些函数来初始化 HDevProcedure 实例。
hdev_engine.set_procedure_path(proc_dir) external_proc = ha.HDevProcedure.load_external('detect_fin') program = ha.HDevProgram(os.path.join(proc_dir, 'program.hdev')) local_proc_program = ha.HDevProcedure.load_local(program, 'count_nuts') local_proc_name = ha.HDevProcedure.load_local('program.hdev', 'count_nuts')
虽然 Python 允许在实例上调用静态方法,例如:ha.HDevProcedure().load_external,但不建议这样做,因为这会不必要地浪费资源。
HDevEngine def unload_procedure(self, name: str) -> None: def unload_all_procedures(self) -> None:
函数加载后,这些函数可以让您再次卸载函数。例如,这对释放未使用的内存非常有用。
通过这些只读成员变量访问函数元数据:
HDevProcedure - name : str - short_description : str - loaded : bool - input_iconic_param_names : List[str] - output_iconic_param_names : List[str] - input_control_param_names : List[str] - output_control_param_names : List[str] - input_iconic_param_dimensions : List[int] - output_iconic_param_dimensions : List[int] - input_control_param_dimensions : List[int] - output_control_param_dimensions : List[int]
HDevProcedure def get_used_procedure_names(self) -> List[str]: def get_info(self, slot: str) -> HTupleType: def get_param_info(self, name: str, slot: str) -> HTupleType: def get_input_iconic_param_info(self, idx: int, slot: str) -> HTupleType: def get_output_iconic_param_info(self, idx: int, slot: str) -> HTupleType: def get_input_control_param_info(self, idx: int, slot: str) -> HTupleType: def get_output_control_param_info(self, idx: int, slot: str) -> HTupleType: def query_slots(self) -> List[str]: def query_param_slots(self) -> List[str]:
使用这些函数可以查询函数元数据。
HDevProcedure def compile_used_procedures(self) -> bool:
编译程序中使用的所有函数,这些函数可以用即时(JIT:Just-In-Time)编译器编译。无法编译的函数将由 HDevEngine 解释器以常规方式调用。要检查哪些函数无法编译以及原因是什么,请启动 HDevelop 并检查编译状态。
此函数返回所有使用的函数是否都经过 JIT 即时编译。
proc_call = ha.HDevProcedureCall(procedure)
初始化 HDevProcedureCall 实例的唯一方法是使用已加载的 HDevProcedure 实例。
HDevProcedureCall def set_input_control_param_by_index(self, idx: int, value: HTupleType) -> None: def set_input_tuple_vector_by_index(self, idx: int, value: TupleVectorType) -> None: def set_input_control_param_by_name(self, name: str, value: HTupleType) -> None: def set_input_tuple_vector_by_name(self, name: str, value: TupleVectorType) -> None: def set_input_iconic_param_by_index(self, idx: int, value: HObject) -> None: def set_input_iconic_vector_by_index(self, idx: int, value: IconicVectorType) -> None: def set_input_iconic_param_by_name(self, name: str, value: HObject) -> None: def set_input_iconic_vector_by_name(self, name: str, value: IconicVectorType) -> None:
这些函数允许您设置输入参数。我们建议您在每次执行函数调用时都重新设置所有输入参数。这有助于使您的代码在面对错误条件时更加稳健。
这里的索引从 1 开始,而不是从 0 开始。
HDevProcedureCall def execute(self) -> None:
当您设置好执行函数的所有输入参数后,请使用此功能。
HDevProcedureCall def get_output_control_param_by_index(self, idx: int) -> HTupleType: def get_output_tuple_vector_by_index(self, idx: int) -> TupleVectorType: def get_output_control_param_by_name(self, name: str) -> HTupleType: def get_output_tuple_vector_by_name(self, name: str) -> TupleVectorType: def get_output_iconic_param_by_index(self, idx: int) -> HObject: def get_output_iconic_vector_by_index(self, idx: int) -> IconicVectorType: def get_output_iconic_param_by_name(self, name: str) -> HObject: def get_output_iconic_vector_by_name(self, name: str) -> IconicVectorType:
调用 execute 成功后,使用这些函数读取输出参数。
这里的索引从 1 开始,而不是从 0 开始。
HDevProcedureCall def wait_for_debug_connection(self) -> None:
将此函数与 start_debug_server 结合使用,可调试程序的执行。
HDevProcedureCall def reset(self) -> None:
这主要适用于想从另一个线程中止执行,或在某些实例仍存活时释放本地资源的情况。
从 Python 调用 HDevelop 程序的一般概念如下:
example_dir = ha.get_system_s('example_dir') program_path = os.path.join( example_dir, 'hdevelop', 'Transformations', 'Poses' ) program = ha.HDevProgram(os.path.join(program_path, 'pose_compose.hdev')) program_call = ha.HDevProgramCall(program) program_call.execute() pose = program_call.get_control_var_by_name('PoseComposeAlternative') rounded_pose = [round(x, 8) for x in pose] assert rounded_pose == [0.3, -0.0498838, 0.33986422, 77.0, 90.0, 0.0, 0]
program = ha.HDevProgram(os.path.join(program_path, 'pose_compose.hdev'))
程序是通过 HDevProgram 初始化器加载的,该初始化器需要操作系统格式的 HDevelop 程序完整路径,包括文件名。
通过这些只读成员变量访问程序元数据:
HDevProgram - name : str - loaded : bool - inconic_var_names : List[str] - control_var_names : List[str] - inconic_var_dimensions : List[int] - control_var_dimensions : List[int]
HDevProgram def get_used_procedure_names(self) -> List[str]: def get_local_procedure_names(self) -> List[str]:
使用这些函数来查询程序元数据。
HDevProgram def compile_used_procedures(self) -> bool:
编译程序中使用的所有函数,这些函数可以用即时编译器编译。无法编译的函数将由 HDevEngine 解释器以常规方式调用。要检查哪些函数无法编译以及原因是什么,请启动 HDevelop 并检查编译状态。
返回是否所有使用的函数都经过即时编译。
program_call = ha.HDevProgramCall(program)
初始化 HDevProgramCall 实例的唯一方法是使用有效的 HDevProgram 实例。
HDevProgramCall def execute(self) -> None:
使用此功能执行程序。
HDevProgramCall def get_control_var_by_index(self, idx: int) -> HTupleType: def get_tuple_vector_var_by_index(self, idx: int) -> TupleVectorType: def get_control_var_by_name(self, name: str) -> HTupleType: def get_tuple_vector_var_by_name(self, name: str) -> TupleVectorType: def get_iconic_var_by_index(self, idx: int) -> HObject: def get_iconic_vector_var_by_index(self, idx: int) -> IconicVectorType: def get_iconic_var_by_name(self, name: str) -> HObject: def get_iconic_vector_var_by_name(self, name: str) -> IconicVectorType:
在 execute 调用成功结束后,使用这些函数读取变量。
这里的索引从 1 开始,而不是从 0 开始。
HDevProgramCall def wait_for_debug_connection(self) -> None:
将此函数与 start_debug_server 结合使用,可调试程序的执行。
HDevProgramCall def reset(self) -> None:
这主要适用于想从另一个线程中止执行,或在某些实例仍存活时释放本地资源的情况。
在HDevelop中,dev_* 算子的使用非常方便。在应用程序中嵌入HDevelop程序或函数时,潜在的dev_* 算子调用没有直接的映射。例如,可能需要将 dev_* 算子调用映射到应用程序中的可视化。因此,HDevEngine/Python 提供了一个基类,您可以继承该基类,并用适合您应用程序的逻辑覆盖它。
例如,这个简单的 HDevelop 程序可以读取图像,然后在开发窗口中显示 PCB 图像。
read_image(Image, 'pcb') dev_display(Image)
默认情况下,该程序在使用 HDevEngine/Python 时不会打开窗口。不过,您可以指定调用 dev_display 时应该发生的逻辑。
例如,这段 Python 代码注册了 dev_display 的一个非常基本的实现。
class DevImpl(ha.HDevOperatorBase): @staticmethod def dev_display(object): print(object) hdev_engine = ha.HDevEngine() hdev_engine.set_hdev_operator_impl(DevImpl())
要了解哪些 dev_* 算子可用,以及每个算子需要哪些签名,请查看 HDevOperatorBase 的实现。
请注意,一次只能注册一个实现。这适用于所有当前和未来的 HDevEngine 实例,直至发生更改。
默认情况下不会注册任何实现。一旦注册了实现,就可以通过调用:
hdev_engine.unset_hdev_operator_impl()
请注意,调用 register_dev_operators 可能会对 Python 变量的生命周期产生令人惊讶的影响。详情请参见该函数的文档。
如果调用未被 HDevOperatorBase 实现覆盖的每个函数,都会引发异常。
在执行 dev_* 算子的 Python 代码中引发异常是安全的。不过,只会引发一个通用的 HDevEngineError,原始异常回溯将被记录到 stderr。这是由于技术上的限制。
HDevEngine/Python 将 HALCON 向量映射为嵌套的 Python 列表。有两种不同的、互不兼容的向量类型:tuple_vector 和 iconic_vector。以下示例演示了在 HDevEngine/Python 中用于读写 HALCON 向量的 Python 表示法:
empty_tuple_vector = ha.HDevEmptyVector(dimension=1) 1d_tuple_vector = [[23, 'a'], ['ec', 2.5, 77]] 2d_tuple_vector = [[[8], ['b', 'c']], [], [[]]] empty_iconic_vector = ha.HDevEmptyVector(dimension=1) 1d_iconic_vector = [img1, img2, img3] 2d_iconic_vector = [[img1, img2], [img1, img3, img4], []]
对于 tuple_vector,最内层列表被视为 HALCON 元组。
向量的所有元素必须具有相同的维度:
[ [234], [2, 5] ] # ok [ 234, [2, 5] ] # not ok
由于 HDevEngine 是一个可变的单例,因此某些功能会影响整个应用程序:
线程应用程序在处理此类共享可变状态时必须小心谨慎。例如,如果多个函数需要不同的路径设置,而应用程序内部又没有进行适当的同步,那么就不能安全地使用全局函数路径并行加载多个函数。不采取必要的谨慎措施将导致未定义的行为,包括崩溃和更严重的情况。
为避免上述问题,我们建议在程序开始时配置 HDevEngine 以及加载函数和程序,然后再启动其他应用程序线程。
与 HDevEngine、HDevProcedure 和 HDevProgram 不同,调用实例 HDevProcedureCall 和 HDevProgramCall 相互独立。