Programmers Guide
Programmers Guide
Copyright © 2003-2019 by MVTec Software GmbH, München, Germany MVTec Software GmbH
Protected by the following patents: US 7,062,093, US 7,239,929, US 7,751,625, US 7,953,290, US 7,953,291, US 8,260,059,
US 8,379,014, US 8,830,229. Further patents pending.
Microsoft, Windows, Windows Server 2008/2012/2012 R2/2016, Windows 7/8/8.1/10, Microsoft .NET, Visual C++, and Visual
Basic are either trademarks or registered trademarks of Microsoft Corporation.
AMD and AMD Athlon are either trademarks or registered trademarks of Advanced Micro Devices, Inc.
Arm is a registered trademark of Arm Limited.
Intel, and Pentium are either trademarks or registered trademarks of Intel Corporation.
Linux is a trademark of Linus Torvalds.
macOS and OpenCL are trademarks of Apple Inc.
NVIDIA, CUDA, cuBLAS, and cuDNN are either trademarks or registered trademarks of NVIDIA Corporation.
OpenGL is a trademark of Silicon Graphics, Inc.
All other nationally and internationally recognized trademarks and tradenames are hereby recognized.
This manual describes the programming language interfaces of HALCON and shows how to use HALCON in
programming languages like C++, C#, C, or Visual Basic. It contains the necessary information to understand and
use the provided data structures and classes in your own programs.
We expect the reader of this manual to be familiar with the programming languages themselves and with the
corresponding development tools.
The manual is divided into the following parts:
• General Issues
This part contains information that is relevant for all programming interfaces, e.g., which interface to use for
which programming language or how to use HALCON with parallel programming.
• Programming With HALCON/C++
This part describes the HALCON’s language interface to C++.
• Programming With HALCON/.NET
This part describes HALCON’s language interface to .NET programming languages (C#, Visual Basic .NET,
etc.).
• Programming With HALCON/C
This part describes HALCON’s language interface to C.
• Using HDevEngine
This part describes how to use HDevEngine to execute HDevelop programs and procedures from a program-
ming language.
Contents
I General Issues 9
1 Which HALCON Interface to Use 11
Index 171
Part I
General Issues
Which HALCON Interface to Use 11
General Issues
Chapter 1
Since the introduction of HALCON/.NET, for many programming languages you can now use more than one
interface. Table 1.1 on page 11 guides you through these possibilities.
recommendation alternative(s)
C → HALCON/C
C++ (unmanaged) → HALCON/C++
C++ (managed) → HALCON/.NET HALCON/C++
C# → HALCON/.NET
Visual Basic .NET → HALCON/.NET
The system requirements and supported platforms are listed in the Installation Guide, section 1.4 on page 8.
12 Which HALCON Interface to Use
Parallel Programming and HALCON 13
General Issues
Chapter 2
This chapter explains how to use HALCON on multi-core or multi-processor hardware, concentrating on the main
features: automatic parallelization (section 2.1 on page 13) and the support of parallel programming (section 2.2
on page 14).
If HALCON is used on multi-processor or multi-core hardware, it will automatically parallelize image processing
operators. Section 2.1.1 on page 13 describes how to initialize HALCON in order to use this mechanism. Sec-
tion 2.1.2 on page 14 explains the different methods which are used by HALCON operators for their automatic
parallelization.
In order to adapt the parallelization mechanism optimally to the actual hardware, HALCON needs to examine this
hardware once. Afterwards, HALCON programs will be automatically parallelized without needing any further
action on your part. Even existing HALCON programs will run and be parallelized without needing to be changed.
You trigger this initial examination by calling the operator optimize_aop (see the corresponding entry in the
HALCON Reference Manuals for further information). Note, that this operator will only work correctly if called
on a multi-core or multi-processor hardware; if you call the operator on a single-processor or single-core computer,
it will return an error message. As a shortcut, you may call the executable hcheck_parallel which resides in the
directory %HALCONROOT%\bin\%HALCONARCH%.
Upon calling optimize_aop, HALCON examines every operator that can be sped up in principle by an automatic
parallelization. Each examined operator is processed several times - both sequentially and in parallel - with a
changing set of input parameter values, e.g., images. The latter helps to evaluate dependencies between an opera-
tor’s input parameter characteristics (e.g. the size of an input image) and the efficiency of its parallel processing.
Note that this examination may take some hours, depending on your computer and the optimization parameters!
The extracted information is stored in the file .aop_info in the common application data folder (under Windows)
or in the HALCON installation directory $HALCONROOT (under Linux). Please note, that on some operating sys-
tems you need special privileges to initialize HALCON successfully, otherwise the operator optimize_aop is not
able to store the extracted information. Note that in order to execute command line tools with administrator
privileges under Windows Vista and higher, you will need to select “Run as Administrator” (even if you are !
already logged in as administrator).
Please refer to the examples in the directory %HALCONEXAMPLES%\hdevelop\System\Parallelization for
more information about optimize_aop and about other operators that allow to query and modify the paralleliza-
tion information.
14 Parallel Programming and HALCON
For the automatic parallelization of operators, HALCON exploits data parallelism, i.e., the property that parts of
the input data of an operator can be processed independently of each other. Data parallelism can be found at four
levels:
1. tuple level
If an operator is called with iconic input parameters containing tuples, i.e., arrays of images, regions, or
XLDs, it can be parallelized by distributing the tuple elements, i.e., the individual images, regions, or
XLDs, on parallel threads. This method requires that all input parameters contain the same number of
tuple elements (or contain a single iconic object or value).
2. channel level
If an operator is called with input images containing multiple channels, it can be parallelized by distributing
the channels on parallel threads. This method requires that all input image objects contain the same number
of channels or a single channel image.
3. domain level
An operator supporting this level can be parallelized by dividing its domain and distributing its parts on
parallel threads.
4. internal data level
Only parts of the operator are parallelized. The actual degree of parallelization depends on the implemen-
tation of the operator. As a result, the potential speedup on multi-core systems varies among operators
utilizing this parallelization method.
The description of a HALCON operator in the Reference Manuals contains an entry called ’Parallelization’, which
specifies its behavior when using HALCON on a multi-core or multi-processor hardware. This entry indicates
whether the operator will be automatically parallelized by HALCON and by which method (tuple, channel, domain,
internal data).
The parallelization method of an arbitrary operator opname can also be determined using get_operator_info:
HALCON supports parallel programming by being thread-safe and reentrant, i.e., different threads can call HAL-
CON operators simultaneously without having to wait. However, not all operators are fully reentrant. This section
takes a closer look at the reentrancy of HALCON. Furthermore, it points out issues that should be kept in mind
when writing parallel programs that use HALCON.
The example program example_multithreaded1.c in the directory example\c shows how to use multithread-
ing to extract different types of components on a board in parallel using HALCON/C.
Furthermore, HALCON provides special operators to synchronize threads (see section 2.2.3 on page 15).
1. reentrant
An operator is fully reentrant if it can be called by multiple threads simultaneously independent of the data
it is called with.
Please note that you must take special care when multiple threads use the same data objects, e.g., the
same image variable. In this case, you must synchronize the access to this variable manually using the
corresponding parallel programming mechanisms (mutexes, semaphores). Better still is to avoid such
cases as far as possible, i.e., to use local variables. Note that this is no special problem of HALCON but of
parallel programming in general.
2.2 Parallel Programming 15
2. local
Operators marked as local should be called only from the thread that instantiates the corresponding objects.
General Issues
3. single write multiple read
A certain group of operators should be called simultaneously only if the different calling threads work on
different data.
As this thread behavior is not recommended quite generally, HALCON does not actively prevent it and
thus saves overhead. This means that if you (accidentally) call such operators simultaneously with the
same data no thread will block, but you might get unwelcome effects.
4. mutually exclusive
Some operators cannot be called simultaneously by multiple threads but may be executed in parallel to
other HALCON operators.
5. exclusive
A group of operators is executed exclusively by HALCON, i.e., while such an operator is executed, all
other threads cannot call another HALCON operator.
6. independent
A group of operators is executed independently from other, even exclusive operators.
As mentioned already, the description of a HALCON operator in the Reference Manuals contains an entry called
’Parallelization’, which specifies its behavior when using HALCON. This entry specifies the level of reentrancy as
described above.
In the operator section “System . Multithreading”, HALCON provides operators for creating and using synchro-
nization objects like mutexes, events, condition variables, and barriers.
16 Parallel Programming and HALCON
With them, you can synchronize threads in a platform-independent way. Note, however, that up to now no operators
for creating the threads are provided.
2.2.4 Examples
HALCON currently provides the following examples for parallel programming (paths relative to %HALCONEXAM-
PLES%):
HALCON/C
• c\source\example_multithreaded1.c
two threads extract different elements on a board in parallel
HALCON/.NET
• c#\MultiThreading (C#)
performs image acquisition, processing, and display in three threads
• hdevengine\c#\MultiThreading (C#)
executes the same HDevelop procedure in parallel by two threads using HDevEngine
• hdevengine\c#\MultiThreadingTwoWindows (C#)
executes different HDevelop procedures in parallel by two threads using HDevEngine
HALCON/C++
• mfc\FGMultiThreading (using MFC)
performs image acquisition / display and processing in two threads
• mfc\MultiThreading (using MFC)
performs image acquisition, processing, and display in three threads
• hdevengine\mfc\source\exec_programs_mt_mfc.cpp
executes HDevelop procedures for image acquisition, data code reading, and visualization in parallel using
HDevEngine and MFC
• hdevengine\cpp\source\exec_procedures_mt.cpp
executes HDevelop programs in parallel using HDevEngine
On Microsoft Windows, accessing a window’s message queue is only possible from the thread that created the
window. Furthermore, a window that has a parent window must be opened in the thread that created the parent
window.
All HALCON graphic operators are automatically redirected to the correct thread. This is done by sending a
special message to the window. To avoid conflicts with user code, the ID of this message is dynamically generated
using the Win32 RegisterWindowMessage function. For windows not created by HALCON (this is relevant
to open_ext_window and when specifying a parent window to open_window, the (non-HALCON) window is
automatically subclassed using the Win32 SetWindowSubclass function. The only requirement for user code is
that for this mechanism to work, each window must have an active message loop.
2.4 Using HALCON with OpenMP 17
To avoid having to write user code to handle the message loop of a HALCON window, HALCON can be instructed
to create all top-level HALCON windows from a special thread via set_system(’use_window_thread’,’true’),
General Issues
which will then also take care of the message loop. Note that this may negatively affect performance if many
windows are used simultaneously, as HALCON provides only a single thread for all windows.
2.3.2 X11
When using the X11 windowing system, either care must be taken to not call HALCON graphic operators from
multiple threads simultaneously, or the X11 function XInitThreads must be called before any other X11 func-
tions. If HALCON drawing objects are used, then XInitThreads must be called regardless. Note that the HAL-
CON library does not call XInitThreads itself, so user code must call XInitThreads even if all usage of X11 is
via HALCON only.
2.3.3 macOS
On macOS, any operation that manipulates the NSView hierarchy must be done from the main thread. Furthermore,
to ensure events are processed in the correct order, any access to the event queue should also be done from the main
thread.
All HALCON graphic operators are automatically redirected to run from the main thread. This is done by using
Grand Central Dispatch to dispatch the execution of HALCON operators as tasks to the main thread’s dispatch
queue. In order for this to work, the main thread must call dispatch_main or configure a run loop as described in
Apple’s “Concurrency Programming Guide” for macOS. Please note that since HALCON uses AppKit to display
windows, the main thread should also be handling events from the window server. Standard Cocoa applications
that call NSApplicationMain satisfy this requirement automatically, but C or C++ code exported by HDevelop
does not, as this requires creating an application bundle, which is beyond the scope of the HDevelop code exporter.
The various HALCON draw_* operators work by actively polling the message (Windows) or event (macOS)
queue. Since all graphics operators are run on the main thread in macOS, only a single draw_* operator can be
active at any given time. On Windows, several draw_* operators can be active if they target windows belonging to
different threads.
Using different OpenMP runtimes in a single program leads to an undefined behavior. Thus, if you have an
application using HALCON and OpenMP, meaning your application uses the hcpudnn library and OpenMP, you
have to link against the Intel OpenMP library libiomp5. The latter one is installed with HALCON. For the linking,
the necessary steps depend on your platform:
With the help of HALCON’s system parameters, which can be set and queried with the operators set_system and
get_system, respectively, you can customize the behavior of the parallelization mechanisms.
You can query the number of processors (or cores) by calling
get_system('processor_num', Information)
You can switch off parts of the features of HALCON with the help of the operator set_system. To switch off
the automatic parallelization mechanism, call (HDevelop notation, see the Reference Manual for more information)
set_system('parallelize_operators','false')
set_system('reentrant','false')
Of course, you can switch on both behaviors again by calling set_system with ’true’ as the second param-
eter. Please note that when switching off reentrancy you also switch off automatic parallelization, as it requires
reentrancy.
Switch off these features only if you are sure you don’t need them but want to save the corresponding computing
overhead. e.g., if you write a sequential program that will never run on a multi-processor or multi-core computer.
A reason for switching off the automatic parallelization mechanism could be if your multithreaded program does
its own scheduling and does not want HALCON to interfere via automatic parallelization. Note that you do not
need to switch off automatic parallelization when using HALCON on a single-processor or single-core computer;
HALCON does so automatically if it detects only one processor or core.
When switching off the automatic parallelization, you might consider switching off the use of thread pools (see the
parameter ’thread_pool’ of set_system).
! Please do not switch on reentrancy if this is already the case! Otherwise, this will reset the parallelization
system, which includes switching on the automatic operator parallelization. This will decrease the performance in
case of manual parallelization (multithreading).
With the system parameter ’parallelize_operators’ you can customize the automatic parallelization mecha-
nisms in more detail. Please see the description of set_system for more information.
Finally, you can influence the number of threads used for automatic parallelization with the parameters
’thread_num’ and ’tsp_thread_num’ (set_system). Reducing the number of threads is useful if you also
perform a manual parallelization in your program. If you switch off automatic parallelization permanently, you
should also switch off the thread pool to save resources of the operating system.
All image acquisition devices supported by HALCON can be used on multi-core or multi-processor hard-
ware. Please note, that none of the corresponding operators is automatically parallelized. Most of the op-
erators are reentrant, only the operators concerned with the connection to the device (open_framegrabber,
info_framegrabber, and close_framegrabber) are processed exclusively in their group, i.e., they block the
concurrent execution of other image acquisition operators but run in parallel with all non-exclusive operators out-
side of this group (see open_framegrabber). Furthermore, these operators are local, i.e., under Windows they
should be called from the thread that instantiates the corresponding object (see section 2.2.1 on page 14).
2.5 Additional Information on HALCON 19
General Issues
By default, HALCON uses spinlocks for synchronization between threads to maximize performance. However,
there are several situations where using spinlocks is not recommended:
1. If there are more threads running than there are CPUs to run them on, performance will be severely reduced.
2. If any threads using HALCON use any form of real-time scheduling (SCHED_FIFO, SCHED_RR, or
SCHED_DEADLINE on Linux systems, REALTIME_PRIORITY_CLASS on Windows systems), HALCON can
deadlock.
To turn spinlocks off, call the function HSetUseSpinLock(0) before calling the first HALCON operator. Please
note that calling HSetUseSpinLock after HALCON has been initialized leads to undefined behaviour.
Spinlocks and the HALCON thread pool
The HALCON thread pool used for the automatic operator parallelization will always use spinlocks, even if HSe-
tUseSpinLock has been called to turn them off. Thus, it is important to make sure the thread pool does not use
more threads than CPUs are actually available to run them on. You must be especially careful if your program uses
any form of real-time scheduling, as your program can deadlock otherwise.
HALCON will normally always create the thread pool during initialization. If you do not need the thread pool,
you can prevent it from being created by calling the function HSetStartUpThreadPool(0) before calling the
first HALCON operator.
HALCON thread pool and CPU affinity on Linux
On Linux systems, threads inherit the CPU affinity of the parent thread that created them. This means that if
the HALCON thread pool is enabled, its threads will be limited by the CPU affinity mask active of the thread
creating the pool at the time the thread pool is created. If the pool is turned off, HALCON’s automatic operator
parallelization will create threads on the fly. These threads will be limited to the CPU affinity mask of the thread
calling the HALCON operator being parallelized.
Please note that HALCON looks at the CPU affinity mask of the process during initialization to determine how
many of the CPUs present can actually be used for automatic operator parallelization only once at startup. Thus,
if you change the CPU affinity subsequently, HALCON will not notice and may end up attempting to use more
CPUs than are available to it. This can degrade performance or lead to deadlocks when using any form of real-time
scheduling. Problems will also ensue if the thread used to initialize HALCON uses a different CPU affinity mask
than its parent process, as HALCON only takes the CPU affinity mask of the process into account.
20 Parallel Programming and HALCON
Tips and Tricks 21
General Issues
Chapter 3
HALCON Spy helps you to debug image processing programs realized with HALCON operators by monitoring
calls to HALCON operators and displaying their input and output data in graphical or textual form. Furthermore,
it allows you to step through HALCON programs. Note that under Windows HALCON Spy does only work in
combination with a console application, i.e., you can not use it together with HDevelop. !
HALCON Spy is activated within a HALCON program by inserting the line
set_spy('mode','on')
Alternatively, you can activate HALCON Spy for an already linked program by defining the environment variable
HALCONSPY (i.e., by setting it to any value). How to set environment variables is described in the Installation
Guide, section A.2 on page 45.
You specify the monitoring mode by calling the operator set_spy again with a pair of parameters, for example
set_spy('operator','on')
set_spy('input_control','on')
to be informed about all operator calls and the names and values of input control parameters. The monitoring mode
can also be specified via the environment variable HALCONSPY, using a colon to separate multiple options:
operator=on:input_control=on
Please take a look at the entry for set_spy in the HALCON Reference Manuals for detailed information on all the
debugging options.
Please note that HALCON Spy cannot be used to debug multithreaded programs or programs using the automatic
parallelization.
If you want to use HALCON Spy on a multi-core or multi-processor hardware, you must therefore first switch off
the automatic parallelization as described in section 2.5.1 on page 18.
In applications where DLLs are unloaded in a thread-exclusive context, e.g., with FreeLibrary() under Win-
dows, the HALCON library will not terminate properly if there are still active HALCON threads.
22 Tips and Tricks
A possible scenario where the problem may occur is, e.g., when using HALCON/C++ to implement an ATL
control.
To overcome this problem, it is necessary to call the function FinalizeHALCONLibrary() before unloading the
DLL. Please note that the application has to be linked against halcon.lib. Make sure that the call to Finalize-
HALCONLibrary() is not from within any other DLL’s DllMain function. Please note that once FinalizeHAL-
CONLibrary() has been called, no further HALCON functions may be called. Please also note that the HALCON
library is not capable to free all resources properly during termination. This might result in memory leaks when
loading and unloading the HALCON library repeatedly.
HALCON includes an extension for the inspection of HALCON variables in Visual Studio (see Installation Guide,
section 1.4 on page 8, for the system requirements). A development license is required for this extension to work
(see Installation Guide, chapter 4 on page 29 for the different license types). If the license is valid for the HALCON
Progress edition, only the corresponding edition of the HALCON Variable Inspect can be used, i.e., HALCON
Progress Variable Inspect requires HALCON Progress. To change the HALCON Variable Inspect edition, you
have to reopen Visual Studio and choose the desired HALCON Variable Inspect edition.
The extension is registered by default for your Visual Studio installation while installing HALCON. In case this op-
tion was deactivated for the installation, you can register the extension manually by double-clicking the following
file:
%HALCONROOT%/misc/HALCON1905ProgressVariableInspect.vsix
If multiple versions of Visual Studio are installed on your machine, the installer will let you select the version(s)
you wish to add the extension to. Once installed, the extension should appear in the side pane of Visual Studio. If
it does not, select Tools → HALCON 19.05 Progress Variable Inspect. Please note that the environment
variable HALCONROOT must be set for the extension to work.
The extension is provided only for the inspection of iconic objects and tuples in the following languages:
Interface Language
HALCON/C++ C++
HALCON/.NET C#, Visual Basic .NET
Note, that Visual Studio Express does not support extensions. Also, note that at the moment the HALCON Vari-
able Inspect does not work with C++/CLI applications. The only supported combinations are native C++ with
HALCON/C++, C# with HALCON/.NET, and Visual Basic .NET with HALCON/.NET.
• Mark a variable in the program code. Then drag and drop the selected variable from the program code to the
“Watch” list.
3.3 Inspecting HALCON Variables in Visual Studio 23
• Right-click on the variable in the program code and select Add to HALCON Watch from the context menu.
General Issues
• Right-click on a variable in the “Locals” list and select Add to Watch from the context menu.
Note that the fewer variables are listed in the inspection window the better the performance. Therefore, moving
only the desired variables to the “Watch” list and inspecting the variables in the Watch tab improves the perfor-
mance.
By default, the variables in the inspection window are listed in the same order as in the Locals window of Visual
Studio. The variables can be sorted in descending or ascending order by clicking on the header of the respective
columns in the inspection window. To switch back to the default order, click on the header of the column “#”.
The table Table 3.2 on page 23 describes which information is displayed for the variables of the “Locals” and
“Watch” list of the inspection window.
Columns Description
# This column contains no values. It can be used to restore the default order of the
variable list by clicking on the header of this column.
Name Name of the local HALCON variable.
Type Type of the local HALCON variable. Only iconic variables and tuples are sup-
ported in the extension.
Status Current status that indicates if the debug information of the variable could be
retrieved. In case it has been successfully retrieved, a green checkmark is dis-
played. If the information could not be retrieved, a red crossmark is displayed.
Status Message Status message for the variable. If the HALCON data of a variable could not be
retrieved, the status message delivers more detailed information about the cause.
If the HALCON data could be retrieved, additional information about the data
is displayed.
The Watch tab of the inspection window gives some additional information about the scope, see Table 3.3 on page
23.
Column Description
Scope Scope of the HALCON variable. For local HALCON variables the scope “Lo-
cal” is returned and for global HALCON variables the scope “Global”. If the
scope could not be determined, i.e., because the variable is not in the current
scope or uninitialized, “Unknown” is returned.
Inside Scope Current status if the HALCON variable is in the current scope of the program.
If the variable is in the current scope, “True” is returned, else “False”.
Table 3.3: Additional columns of the variable list in the Watch tab.
To select a variable for the inspection, click on the corresponding entry in the variable list of the inspection window.
If the debug information and HALCON data of the variable has already been retrieved, i.e., if Status has a green
checkmark, the value of the variable is displayed. Otherwise, the retrieval of the HALCON data is started and the
value of the variable is displayed if the data could be retrieved. To enforce a complete new retrieval of the data,
even for variables whose data have already been obtained, double-click on the variable. The inspection window is
automatically updated if the content of the currently displayed variable changes.
To deselect a variable, press CTRL and click on the respective line of the variable. Alternatively, right-click on the
line of the variable and select Deselect all from the context menu. In some cases it is desired to display the
data of a variable again. This can be achieved by deselecting and selecting the variable again or by double-clicking
on it.
If a member of a variable cannot be resolved, e.g., if the variable is related to a class, it is not sufficient to inspect
only the member of this variable. Instead, mark the complete expression before right-clicking and inspecting the
member variable.
Please note that native 64-bit data types, e.g., int8 images, and image data with a size > 0.5 GB are not supported.
24 Tips and Tricks
• Name of the iconic variable, type, number of channels (for images), and the dimensions (for images).
• Gray value (v), row (r), and column (c) at the mouse position
Iconic variables may be stacked: For example, image data may be overlayed with region data by first inspecting
the image variable and then the region variable.
Getting Help
You can open the operator reference of a specific operator right from the context menu of Visual Studio. Move the
mouse cursor over a method name, right-click on it and select HALCON Help.
3.4 Handling Licensing Errors 25
Persistent Settings
General Issues
The following settings are persistent between sessions:
When running HALCON with a runtime license and a dongle, HALCON checks regularly whether the dongle is
still available. This check has no measurable impact on the performance of HALCON.
In order to be notified if the dongle was removed and a license error is imminent, applications can register a
callback function with HALCON that will be called when HALCON detects that the dongle is no longer available.
HALCON operators will fail with licensing errors after about two to four minutes after this callback fires. If the
dongle is reinserted before this time, HALCON will continue to operate normally.
Please note that if you do not register a callback and the dongle becomes unavailable during runtime, HALCON
operators will fail with a license error and will therefore not provide meaningful output parameters. Depending on
your application, this might even lead to crashes. It is highly suggested to handle errors from operators correctly
or register the callback to notify the user and/or shut down the application in a controlled way.
To register your own callback function, use the following code in your application:
HSetLicenseRecheckFailedCallback(MyLicenseRecheckFailedCallback,
&MyLicenseRecheckFailedContext);
MyLicenseRecheckFailedContext is a user-defined structure that you can use to pass extra information to your
callback. If you do not need this, you can pass a NULL pointer instead.
To unregister a callback, simply call HSetLicenseRecheckFailedCallback with a NULL pointer as argument.
Note that callbacks are not chained – registering a callback will overwrite any previously registered callback.
For example, in your application, you might implement a proper licensing error handling like this:
To check whether a license is available at all, you can use any operator at the beginning of your application and
check the result.
26 Tips and Tricks
Herror error;
Htuple param, value;
create_tuple_s(¶m, "version");
set_check("~give_error");
error = T_get_system(param, &value);
destroy_tuple(value);
destroy_tuple(param);
try
{
HalconCpp::HTuple value = HalconCpp::HSystem::GetSystem("version");
}
catch (HalconCpp::HException &exception)
{
if ( (exception.ErrorCode() >= H_ERR_LIC_NO_LICENSE)
&& (exception.ErrorCode() <= H_ERR_LAST_LIC_ERROR))
{
// Handle licensing error here.
}
}
This section gives some general hints for developing graphical applications.
If you are using graphical user interface (GUI) frameworks, each dialog is managed by a user interface (UI)
thread. The UI thread is responsible for updating the GUI and the execution of callbacks. This means that the
GUI is blocked as long as the UI thread executes the callback. Therefore, callbacks should require as little time as
possible.
If you are using HDevEngine, we recommend to divide your programming tasks into at least two categories: image
processing and visualisation.
For image processing tasks that are initiated by a user action you should start a new thread that handles those
tasks. As soon as the image processing is finished, the UI thread should fetch and display the results. For more
information, please refer to our multithreading example program:
%HALCONEXAMPLES%/c#/MultiThreading
Part II
Chapter 4
C++
Introducing HALCON/C++
HALCON/C++ is HALCON’s interface to the programming language C++. Together with the HALCON library,
it allows to use the image processing power of HALCON inside C++ programs.
This part is organized as follows:
• In section 4.1 on page 29, we start with a first example program.
• Chapter 5 on page 31 then takes a closer look at the basics of the HALCON/C++ interface,
• while chapter 6 on page 41 gives an overview of the classes HImage, etc.
• Chapter 7 on page 47 shows how to create applications based on HALCON/C++.
• Chapter 8 on page 53 presents typical image processing problems and shows how to solve them using HAL-
CON/C++.
Figure 4.1: The left side shows the input image (a mandrill), and the right side shows the result of the image
processing: the eyes of the monkey.
The input image is shown in figure 4.1 on the left side. The task is to find the eyes of the monkey by segmentation.
The segmentation of the eyes is performed by the C++ program listed in figure 4.2, the result of the segmentation
process is shown in figure 4.1 on the right side.
The program is more or less self-explaining. The basic idea is as follows: First, all pixels of the input image are
selected which have a gray value of at least 128, on the assumption that the image Mandrill is a byte image with
a gray value range between 0 and 255. Secondly, the connected component analysis is performed. The result of the
HALCON operator is an array of regions. Each region is isolated in the sense that it does not touch another region
30 Introducing HALCON/C++
#include "HalconCpp.h"
int main()
{
using namespace HalconCpp;
according to the neighbourhood relationship. Among these regions those two are selected which correspond to the
eyes of the monkey. This is done by using shape properties of the regions, the size and the anisometry.
This example shows how easy it is to integrate HALCON operators in any C++ program. Their use is very intu-
itive: You don’t have to care about the underlying data structures and algorithms, you can ignore specific hardware
requirements, if you consider e.g. input and output operators. HALCON handles the memory management effi-
ciently and hides details from you, and provides an easy to use runtime system.
Basics of the HALCON/C++ Interface 31
Chapter 5
C++
Basics of the HALCON/C++ Interface
The HALCON/C++ interface provides two different approaches to use HALCON’s functionality within your C++
program: a procedural and an object-oriented approach. The procedural approach corresponds to calling HAL-
CON operators directly as in C or HDevelop, e.g.:
In addition to the procedural approach, HALCON/C++ allows to call HALCON operators in an object-oriented
way, i.e., via a set of classes. For example, the code from above can be “translated” into:
HImage original_image("monkey");
HImage smoothed_image = original_image.MeanImage(11, 11);
This simple example already shows that the two approaches result in clearly different code: The operator calls
differ in the number and type of parameters. Furthermore, functionality may be available in different ways; for
example, images can be read from files via a constructor of the class HImage. In general, we recommend to use
the object-oriented approach. Note, however, that HDevelop can export programs only as procedural C++ code.
Section 5.5 on page 39 shows how to combine procedural with object-oriented code.
In the following sections, we take a closer look at various issues regarding the use of the HALCON/C++ interface;
chapter 6 on page 41 describes the provided classes in more detail.
• locally, by placing the directive using namespace HalconCpp; at the beginning of a block, e.g., at the
beginning of a function:
int main(int argc, char *argv[])
{
using namespace HalconCpp;
void MeanImage (const HObject& Image, HObject* ImageMean, const HTuple& MaskWidth,
const HTuple& MaskHeight)
HImage HImage::MeanImage (Hlong MaskWidth, Hlong MaskHeight) const
Image (input_object) . . . (multichannel-)image(-array) ; HImage (byte / int2 / uint2 / int4 / int8 / real / vec-
tor_field)
ImageMean (output_object) . . . (multichannel-)image(-array) ; HImage (byte / int2 / uint2 / int4 / int8 / real /
vector_field)
MaskWidth (input_control) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . extent.x ; HTuple (Hlong)
MaskHeight (input_control) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . extent.y ; HTuple (Hlong)
Figure 5.1: The head and parts of the parameter section of the reference manual entry for mean_image.
Then, you can use HALCON’s classes and functions without prefix inside this block.
• globally, by placing the directive using directly after including HalconCpp.h. Then, you do not need the
prefix in your whole application.
#include "HalconCpp.h"
using namespace HalconCpp;
Which method is the most suitable depends on your application, more exactly on what other libraries it includes
and if there are name collisions.
Please note that the namespace is not mentioned in the operator descriptions in the reference manual in order to
keep it readable. Similarly, in the following sections the namespace is left out.
HALCON distinguishes two types of parameters: iconic and control parameters. Iconic parameters are related
to the original image (images, regions, XLD objects), whereas control parameters are values such as integers,
floating-point numbers, strings, or handles.
A special form of control parameters are the so-called handles. A well-known representative of this type is the
window handle, which provides access to an opened HALCON window, e.g., to display an image in it. Besides,
handles are used when operators share complex data, e.g., the operators for shape-based matching which cre-
ate and then use the model data, or for accessing input/output devices, e.g., image acquisition devices. Classes
encapsulating handles are described in detail in section 6.2.3 on page 43.
Both iconic and control parameters can appear as input and output parameters of a HALCON operator. For ex-
ample, the operator MeanImage expects one iconic input parameter, one iconic output parameter, and two input
5.2 Calling HALCON Operators 33
void FindBarCode (const HObject& Image, HObject* SymbolRegions, const HTuple& BarCodeHandle,
const HTuple& CodeType, HTuple* DecodedDataStrings)
HRegion HBarCode::FindBarCode (const HImage& Image, const HTuple& CodeType,
HTuple* DecodedDataStrings) const
HRegion HBarCode::FindBarCode (const HImage& Image, const HString& CodeType,
HString* DecodedDataStrings) const
HRegion HBarCode::FindBarCode (const HImage& Image, const char* CodeType,
HString* DecodedDataStrings) const
HRegion HBarCode::FindBarCode (const HImage& Image, const wchar_t* CodeType,
C++
HString* DecodedDataStrings) const
HRegion HImage::FindBarCode (const HBarCode& BarCodeHandle, const HTuple& CodeType,
HTuple* DecodedDataStrings) const
HRegion HImage::FindBarCode (const HBarCode& BarCodeHandle, const HString& CodeType,
HString* DecodedDataStrings) const
HRegion HImage::FindBarCode (const HBarCode& BarCodeHandle, const char* CodeType,
HString* DecodedDataStrings) const
HRegion HImage::FindBarCode (const HBarCode& BarCodeHandle, const wchar_t* CodeType,
HString* DecodedDataStrings) const
Figure 5.2: The head and parts of the parameter section of the reference manual entry for find_bar_code.
control parameters (see figure 5.1); figure 5.2 shows an operator which has all four parameter types. Note how
some parameters “disappear” from within the parentheses if you call an operator via a class; this mechanism is
described in more detail in section 5.2.2 on page 34.
An important concept of HALCON’s philosophy regarding parameters is that input parameters are not modified
by an operator. As a consequence, they are passed by value (e.g., Hlong MaskWidth in figure 5.1) or via a
constant reference (e.g., const HObject& Image). This philosophy also holds if an operator is called via a class,
with the calling instance acting as an input parameter. Thus, in the following example code the original image is
not modified by the call to MeanImage; the operator’s result, i.e., the smoothed image, is provided via the return
value instead:
HImage original_image("monkey");
HImage smoothed_image = original_image.MeanImage(11, 11);
In contrast to input parameters, output parameters are always modified, thus they must be passed by reference.
Note that operators expect a pointer to an already existing variable or class instance! For example, when calling
the operator FindBarCode as in the following lines of code, variables of the class HTuple are declared before
passing the corresponding pointers using the operator &.
HImage image("barcode/ean13/ean1301");
HBarCode barcode(HTuple(), HTuple());
HString result;
The above example shows another interesting aspect of output parameters: When calling operators via classes, one
output parameter may become the return value (see section 5.2.2 on page 34 for more details); in the example,
FindBarCode returns the bar code region.
34 Basics of the HALCON/C++ Interface
void InfoFramegrabber (const HTuple& Name, const HTuple& Query, HTuple* Information,
HTuple* ValueList)
static HString HInfo::InfoFramegrabber (const HString& Name, const HString& Query, HTuple* ValueList)
static HString HInfo::InfoFramegrabber (const char* Name, const char* Query, HTuple* ValueList)
static HString HInfo::InfoFramegrabber (const wchar_t* Name, const wchar_t* Query, HTuple* ValueList)
Figure 5.3: The head and parts of the parameter section of the reference manual entry for info_framegrabber.
Many HALCON operators accept more than one value for certain parameters. For example, you can call the
operator MeanImage with an array of images (see figure 5.1); then, an array of smoothed images is returned. This
is called the tuple mode; see section 5.2.5 on page 36 for more information.
String Parameters
Regardless of the encoding of the HALCON library (set_system(’filename_encoding’, ...)) the HAL-
CON/C++ interface expects raw char pointer strings that are passed to HALCON operators and to HTuple or
HString instances to be UTF-8 encoded.
Output strings are always of type HString with automatic memory management. These strings are by default
also UTF-8 encoded. The encoding of the HALCON/C++ interface (interface encoding) can be changed to local-
8-bit encoding via a call of HalconCpp::SetHcppInterfaceStringEncodingIsUtf8(false). The current
interface encoding can be requested via HalconCpp::IsHcppInterfaceStringEncodingUtf8(). It is not rec-
ommended to switch the interface encoding back and forth. The setting should be adjusted only once at the very
beginning of the program (before the first HALCON operator or assignment), because HTuple instances can not
store in which encoding the contained strings are present, i.e, for all write and read accesses, the same encoding
must be set. Furthermore, the interface encoding is set globally and is therefore not suitable for multithreading
programs: Changing the setting in one thread has an effect on other threads.
In the following example code, the operator InfoFramegrabber (see also figure 5.3) is called with two output
string parameters to query the currently installed image acquisition board:
Note that it is also not necessary to allocate memory for multiple output string parameters returned as HTuple:
As already described in the previous section, the HALCON/C++ reference manual shows via which classes an
operator can be called. For example, FindBarCode can be called via objects of the class HImage or HBarCode (see
figure 5.2 on page 33). In both cases, the corresponding input parameter (Image or BarCodeHandle, respectively)
does not appear within the parentheses anymore as it is replaced by the calling instance of the class (this).
There is a further difference to the procedural operator signature: The first output parameter (in the example the bar
code region SymbolRegions) also disappears from within the parentheses and becomes the return value instead
of the error code (more about error handling can be found in section 5.3 on page 37).
5.2 Calling HALCON Operators 35
HImage image("barcode/ean13/ean1301");
HBarCode barcode(HTuple(), HTuple());
HString result;
HObject image;
C++
HTuple barcode;
HObject code_region;
HTuple result;
ReadImage(&image, "barcode/ean13/ean1301");
CreateBarCodeModel(HTuple(), HTuple(), &barcode);
FindBarCode(image, &code_region, barcode, "EAN-13", &result);
Figure 5.4: Using FindBarCode via HBarCode, via HImage, or in the procedural approach.
Figure 5.4 depicts code examples for the three ways to call FindBarCode. When comparing the object-oriented
and the procedural approach, you can see that the calls to the operators ReadImage and CreateBarCodeModel
are replaced by special constructors for the classes HImage and HBarCode, respectively. This topic is discussed in
more detail below.
As can be seen in figure 5.4 on page 35, the HALCON/C++ parameter classes provide additional constructors,
which are based on suitable HALCON operators. The constructors for HImage and HBarCode used in the example
are based on ReadImage and CreateBarCodeModel, respectively.
As a rule of thumb: If a class appears only as an output parameter in an operator, there automatically exists a con-
structor based on this operator. Thus, instances of HBarCode can be constructed based on CreateBarCodeModel
as shown in figure 5.4 on page 35, instances of HShapeModel based on CreateShapeModel, instances of
HFramegrabber based on OpenFramegrabber and so on. Note that for classes where many such operators
exist (e.g., HImage), only a subset of commonly used operators with unambiguous parameter list are actually used
as constructor.
In addition, all classes have empty constructors to create an uninitialized object. For example, you can create an
instance of HBarCode with the default constructor and then initialize it using CreateBarCodeModel as follows:
HBarCode barcode;
barcode.CreateBarCodeModel(HTuple(), HTuple());
If the instance was already initialized, the corresponding data structures are automatically destroyed before con-
structing and initializing them anew (see also section 5.2.4). The handle classes are described in more detail in
section 6.2.3.2 on page 44.
Below we take a brief look at the most important classes. A complete and up-to-date list of available constructors
can be found in the HALCON operator reference and the corresponding header files in %HALCONROOT%\include\
cpp.
• Images:
The class HImage provides constructors based on the operators ReadImage, GenImage1, and
GenImageConst.
36 Basics of the HALCON/C++ Interface
• Regions:
The class HRegion provides constructors based on operators like GenRectangle2 or GenCircle.
• Windows:
The class HWindow provides a constructor based on the operator OpenWindow.
Of course, you can close a window using CloseWindow and then open it again using OpenWindow. In
contrast to the iconic parameter classes, you can call the “constructor-like” operator OpenWindow via an
instance of HWindow in the intuitive way, i.e., the calling instance is modified; in addition the corresponding
handle is returned. HWindow is described in more detail in section 6.2.3.1 on page 44.
All HALCON/C++ classes provide default destructors which automatically free the corresponding memory.
The default destructors of classes encapsulating handles, e.g., HShapeModel or HFramegrabber, work similar to
members like ClearShapeModel or CloseFramegrabber, respectively.
There is no need to call these operators as you can initialize instances anew as described in section 5.2.3.
Basically, we differentiate between destroying a handle and destroying the underlying data structure. The data
structure can be destroyed in two ways: Automatically as soon as the last reference to the data structure has been
deleted. Explicitly by calling an operator, e.g., CloseWindow. Explicit destruction invalidates references, but
access is secure.
As already mentioned in section 5.2.1 on page 32, many HALCON operators can be called in the so-called tuple
mode. In this mode, you can, e.g., apply an operator to multiple images or regions with a single call. The standard
case, e.g., calling the operator with a single image, is called the simple mode. Whether or not an operator supports
the tuple mode can be checked in the reference manual. For example, take a look at figure 5.5, which shows an
extract of the reference manual entry for the operator CharThreshold: In the parameter section, the parameter
Image is described as an image(-array); this signals that you can apply the operator to multiple images at once.
If you call CharThreshold with multiple images, i.e., with an image tuple, the output parameters automat-
ically become tuples as well. Consequently, the parameters Characters and Threshold are described as
region(-array) and integer(-array), respectively.
Note that the class HTuple can also contain arrays (tuples) of control parameters of mixed type; please refer to
section 6.2.1 on page 42 for more information about this class. In contrast to the control parameters, the iconic
void CharThreshold (const HObject& Image, const HObject& HistoRegion, HObject* Characters,
const HTuple& Sigma, const HTuple& Percent, HTuple* Threshold)
HRegion HImage::CharThreshold (const HRegion& HistoRegion, double Sigma, const HTuple& Percent,
HTuple* Threshold) const
HRegion HImage::CharThreshold (const HRegion& HistoRegion, double Sigma, double Percent,
Hlong* Threshold) const
Figure 5.5: The head and parts of the parameter section of the reference manual entry for CharThreshold.
5.3 Error Handling 37
HImage image("alpha1");
HRegion region;
Hlong threshold;
HObject image;
C++
HObject region;
HTuple threshold;
ReadImage(&image, "alpha1");
CharThreshold(image, image, ®ion, 2, 95, &threshold);
DispObj(image, window);
DispObj(region, window);
cout << "Threshold for 'alpha1': " << threshold.ToString();
Figure 5.6: Using CharThreshold in simple mode, via HImage, or in the procedural approach (declaration and open-
ing of window omitted).
parameters remain instances of the class HObject in both modes, as this class can contain both single objects and
object arrays.
In the object-oriented approach, control parameters can be of a basic type (simple mode only) or instances of
HTuple (simple and tuple mode).
After this rather theoretic introduction, let us take a look at example code. In figure 5.6, CharThreshold is applied
in simple mode, i.e., to a single image, in figure 5.7 to two images at once. Both examples are realized both in the
object-oriented and in the procedural approach. The examples highlight some interesting points:
• Access to iconic objects:
As expected, in the object-oriented approach, the individual images and regions are accessed via the array
operator []; the number of objects in an array can be queried via the method CountObj(). In the procedural
approach, objects must be selected explicitly using the operator SelectObj; the number of objects can be
queried via CountObj.
Note that object indexes start with 1 (as used by SelectObj).
• Polymorphism of HObject:
The class HObject is used for all types of iconic objects. What is more, image objects can be used for
parameters expecting a region, as in the call to CharThreshold in the examples; in this case, the domain
of the image, i.e., the region in which the pixels are “valid”, is extracted automatically. The object-oriented
approach supports an implicit cast from HImage to HRegion.
Error handling is fully based on exceptions using try ... catch blocks.
The following code shows how to catch and evaluate errors that might occur when reading an image from file. The
call to ReadImage is encapsulated by a try block; the error code of the exception is evaluated in a corresponding
catch block. For more information on HALCON error codes please refer to the Extension Package Programmer’s
Manual, appendix A on page 103.
38 Basics of the HALCON/C++ Interface
HImage images;
HRegion regions;
HTuple thresholds;
images.GenEmptyObj();
for (int i=1; i<=2; i++)
{
images = images.ConcatObj(HImage(HTuple("alpha") + i));
}
GenEmptyObj(&images);
Figure 5.7: Using CharThreshold in tuple mode, or in the procedural approach (declaration and opening of window
omitted).
try
{
image.ReadImage(filename);
}
catch (HException &except)
{
if (except.ErrorCode() == H_ERR_FNF)
{
// Handle file not found error
}
else
{
// Pass on unexpected error to caller
throw except;
}
}
5.4 Memory Management 39
All of HALCON’s classes, i.e., not only HImage, HRegion, HTuple, HFramegrabber etc., but also the class
HObject used when calling operators in the procedural approach, release their allocated resources automatically
in their destructor (see also section 5.2.4 on page 36). Furthermore, when constructing instances anew, e.g., by
calling CreateBarCodeModel via an already initialized instance as mentioned in section 5.2.3 on page 35, the
already allocated memory is automatically released before reusing the instance. Thus, there is no need to call
C++
the operator ClearObj in HALCON/C++; what is more, if you do use it HALCON will complain about already
released memory. To explicitly release the resources before the instance gets out of scope, you can call the method
Clear() of the instance.
As already noted, we recommend to use the object-oriented approach wherever possible. However, there are some
reasons for using the procedural approach, e.g., if you want to quickly integrate code that is exported by HDevelop,
which can only create procedural code.
The least trouble is caused by the basic control parameters as both approaches use the elementary types long etc.
and the class HTuple. Iconic parameters and handles can be converted as follows:
HImage o_image(p_image);
Iconic parameters can be converted from HObject to, e.g., HImage simply by calling the constructor with
the procedural variable as a parameter.
• Converting handles into specific handle classes
HTuple p_barcode;
CreateBarCodeModel(HTuple(), HTuple(), &p_barcode);
HBarCode o_barcode(p_barcode.H());
o_code_region = o_barcode.FindBarCode(o_image, "EAN-13", &result);
Note that instances of HImage can be used in procedural code where HObject is expected.
As already remarked in section 5.2.4 on page 36, you must not use operators like ClearShapeModel,
ClearAllShapeModels, or CloseFramegrabber together with instances of the corresponding handle classes!
HALCON/C++ provides iostream operators by default. Note that it may be necessary to enable the namespace
std:
If you want to use the older iostream interface (i.e., <iostream.h> instead of <iostream>), the following line
has to be added (otherwise, there may be conflicts with the HALCON include files):
#define HCPP_NO_USE_IOSTREAM
40 Basics of the HALCON/C++ Interface
FindText, CreateMutex, CreateEvent, and DeleteFile are also functions of the Windows API. There are
defines on FindTextW, CreateMutexW, CreateEventW, and DeleteFileW if UNICODE is defined, otherwise there
are defines on FindTextA, CreateMutexA, CreateMutexA, and DeleteFileA. These defines are undefined in
HalconCpp.h. If you want to use the corresponding Windows API calls, you must use FindTextA, FindTextW,
CreateMutexA, CreateMutexW, CreateEventA, CreateEventW, DeleteFileA, or DeleteFileW directly.
The HALCON Parameter Classes 41
Chapter 6
C++
The HALCON Parameter Classes
The HALCON operator reference contains a complete list of the generic classes and member functions of HAL-
CON/C++. This chapter contains a summary of additional convenience members.
In addition, HALCON/C++ contains many operator overloads, which are consistent with HALCON/.NET. See
section 10.5.4 on page 69 for a list of the overloaded operators.
6.1.1 Regions
A region is a set of coordinates in the image plane. Such a region does not need to be connected and it may contain
holes. A region can be larger than the actual image format. Regions are represented by the so-called runlength
coding in HALCON. The class HRegion represents a region in HALCON/C++. Besides those operators that can
be called via HRegion (see also section 5.2.2 on page 34), HRegion provides the following member functions:
• HTuple HRegion::Area()
Area of the region, i.e., number of pixels, see reference manual entry of AreaCenter.
• HTuple HRegion::Row()
Center row of the region.
• HTuple HRegion::Column()
Center column of the region.
6.1.2 Images
There is more to HALCON images than just a matrix of pixels: In HALCON, this matrix is called a channel, and
images may consist of one or more such channels. For example, gray value images consist of a single channel,
color images of three channels. Channels can not only contain the standard 8 bit pixels (pixel type byte) used
42 The HALCON Parameter Classes
to represent gray value images, HALCON allows images to contain various other data, e.g. 16 bit integers (type
int2) or 32 bit floating point numbers (type real) to represent derivatives. Besides the pixel information, each
HALCON image also stores its so-called domain in form of a HALCON region. The domain can be interpreted as
a region of interest, i.e., HALCON operators (with some exceptions) restrict their processing to this region.
• HTuple HImage::Width()
Return the width of the image, see reference manual entry of GetImageSize.
• HTuple HImage::Height()
Return the height of the image, see reference manual entry of GetImageSize.
XLD is the abbreviation for eXtended Line Description. This is a data structure used for describing areas (e.g.,
arbitrarily sized regions or polygons) or any closed or open contour, i.e., also lines. In contrast to regions, which
represent all areas at pixel precision, XLD objects provide subpixel precision. There are two basic XLD structures:
contours and polygons.
HALCON/C++ provides both a base class HXLD and a set of specialized classes derived from HXLD, e.g., HXLDCont
for contours or HXLDPoly for polygons.
In contrast to the classes described in the previous sections, the XLD classes provide only member functions
corresponding to HALCON operators (see also section 5.2.2 on page 34).
6.2.1 Tuples
The class HTuple implements an array of dynamic length. The default constructor constructs an empty array
(Length() == 0). This array can dynamically be expanded via assignments. The memory management, i.e.,
reallocation, freeing, is also managed by the class. The index for accessing the array is in the range between 0 and
Length() − 1.
The class HTuple is thread safe. Copies of a HTuple instance can be used in different threads concurrently.
The following member functions reflect only a small portion of the total. For further information please refer to
the file HTuple.h in %HALCONROOT%\include\halconcpp.
• HTuple &HTuple::Append(const HTuple& tuple)
Append data to existing tuple.
• void HTuple::Clear()
Clear all data inside the tuple.
6.2 Control Parameters 43
• HTuple HTuple::Clone()
Create a detached copy duplication the tuple data.
• Hlong HTuple::Length()
Return the number of elements of the tuple.
• HTupleType HTuple::Type()
Return the data type of the tuple (pure data types or mixed tuple).
• HString HTuple::ToString()
Return a simple string representation of the tuple contents.
C++
• Hlong* HTuple::LArr()
double* HTuple::DArr()
char** HTuple::SArr()
Hcpar* HTuple::PArr()
Hphandle* HTuple::HArr()
Access tuple data.
String Encoding
The class HTuple always stores raw char pointer strings in the interface encoding. This is important especially
when accessing the internal raw pointer via the methods HTuple::SArr() and HTupleElement::C().
Under Windows it is possible to initialize a HTuple or a HTupleElement with a wide character string (wchar_t*,
UTF-16). That wide character string is converted into the current interface encoding (default: UTF-8). If that
interface encoding is not UTF-8, the conversion can involve transcoding errors, i.e., the stored string may not
contain all characters of the input wide character string. The class HTuple does not allow to access the string in a
different encoding or as wide character string.
6.2.2 Strings
The class HString can be used when transcoding or access to a wide character raw pointer is needed. Like
HTuple, the class can be initialized with a wchar_t pointer string (Windows only) or with a raw char pointer
string with the current interface encoding. HString allows to create a string with a specific encoding via
HString::FromUtf8(const char*) or HString::FromLocal8bit(const char*).
Furthermore, this class allows to store the same string in UTF-8, local-8-bit encoding, and wide character string at
the same time. Thus it is save to use the required raw pointer, as long as the HString instance is not modified or
destroyed. The string remains the owner of the string memory for all representations.
The following methods for accessing raw pointers are provided:
The perhaps most prominent handle class is HWindow, which is described in section 6.2.3.1. HALCON/C++ also
provides classes for handles to files or functionality like access to image acquisition devices, measuring, or shape-
based matching. See section 6.2.3.2 on page 44 for an overview.
44 The HALCON Parameter Classes
6.2.3.1 Windows
The class HWindow provides the management of HALCON windows in a very convenient way. The properties of
HALCON windows can be easily changed, images, regions, and polygons can be displayed, etc. Besides those
operators that can be called via HWindow (see also section 5.2.2 on page 34), HWindow provides the following
member functions:
• void HWindow::Click()
Wait for a mouse click in the window.
• void HWindow::CloseWindow()
Close the window.
HALCON/C++ provides the so-called handle classes like HFramegrabber, HBarCode, or HClassMlp. These are
based on the class HHandle.
Besides the default constructor, the classes typically provide additional constructors based on suitable operators
as described in section 5.2.3 on page 35; e.g., the class HBarCode provides a constructor based on the operator
CreateBarCodeModel.
The reference manual provides short overview pages for these classes, listing the operators that can be called via
them.
6.3 Vectors
HALCON/C++ provides the class HVector for the use of HALCON vectors in C++ programs. A HALCON vector
is a container that can hold an arbitrary number of elements of the identical data type (i.e., tuple, iconic object,
or vector) and dimension. The type of a vector, i.e., its dimension and the type of its elements is defined when
initializing the vector instance and cannot be changed during its lifetime. A vector with one dimension may be a
vector of tuples or a vector of iconic objects. A two-dimensional vector may be a vector of vectors of tuples or a
vector of vectors of iconic objects, and so on.
Two classes are derived from the root class HVector:
In the following some basic information on how to use vectors in HALCON/C++ is given, e.g., how to construct
vectors and how to access and set vector elements. For a complete list of the available functionality please refer to
the corresponding header file HVector.h in %HALCONROOT%\include\halconcpp.
Construction of Vectors
As already mentioned above, a distinction is made between vectors of iconic objects (HObjectVector) and vectors
of tuples (HTupleVector). The type of a vector must be defined at its construction as in the following lines:
Note that the type of the vector cannot be changed within a program after its construction. Thus, a tuple cannot be
assigned to a vector of iconic objects and vice versa.
To create a two-dimensional vector, i.e., a vector of vectors of iconic objects or a vector of vector of tuples you
may use the following line:
6.3 Vectors 45
You can also create a multi-dimensional vector with more than two dimensions by specifying the desired dimension
in brackets. However, the dimension of a vector is part of its type and has to remain constant within the program
and cannot be changed.
Note that the vectors created by these calls are still empty. How to set the elements of vectors and how to access
C++
them is described below.
The vector element to be accessed is addressed by the specified index in square brackets. If a subelement of a
multi-dimensional vector is to be accessed, you have to use the indices of the corresponding subvector and its
subelement instead.
The left index vec_index defines the index of the subvector and elem_index defines the desired element of the
specified subvector.
If a vector element is to be set, the expression for accessing a vector element is used as reference to the HObject
or HTuple element to be set. The right side of the assignment specifies the value which is assigned to the vector
element.
In the example code above the Image is copied and set as the first vector element of vectorObj. The tuple is also
copied and set as first vector element of vectorTup.
Setting a subelement of a multi-dimensional vector can be done with the same call. However, instead of a single
index, multiple indices must be specified for the corresponding vector element and its subelement, which is to be
set.
It is also allowed to write to a non-existing vector element. Then, the vector is automatically filled with empty
elements if necessary.
46 The HALCON Parameter Classes
Destruction of a Vector
If a vector is not needed anymore for further processing, its contents can be cleared with the following call,
explicitly:
vectorTup.Clear();
Additional Information
In addition to the described functionalities HObjectVector and HTupleVector provide some more functionality
for the use of HALCON vectors in HALCON/CPP, e.g., inserting or removing vector elements, or concatenation
of vectors. Please refer to the corresponding header file HVector.h in %HALCONROOT%\include\halconcpp for
more information.
Creating Applications With HALCON/C++ 47
Chapter 7
C++
Creating Applications With
HALCON/C++
The HALCON distribution contains examples for creating an application with HALCON/C++. The following
sections show
• the relevant directories and files (section 7.1 on page 47)
• the list of provided example applications (section 7.2 on page 48)
• the relevant environment variables (section 7.3 on page 49)
• how to store source files with non-ASCII characters (section 7.4 on page 49)
• how to create an executable under Windows (section 7.5 on page 49)
• how to create an executable under Linux (section 7.6 on page 50)
• how to create an executable under macOS (section 7.7 on page 51)
Here is an overview of the relevant directories and files (relative to %HALCONROOT%, Windows notation of paths):
include:
include directory; contains, e.g., Halcon.h, which is referenced by HalconCpp.h.
include\halconcpp\HalconCpp.h:
include file; contains all user-relevant definitions of the HALCON system and the declarations necessary for
the C++ interface.
bin\%HALCONARCH%\halcon.dll,
lib\%HALCONARCH%\halcon.lib:
The HALCON library (Windows).
bin\%HALCONARCH%\halconcpp.dll,
lib\%HALCONARCH%\halconcpp.lib:
The HALCON/C++ library (Windows).
bin\%HALCONARCH%\halconxl.dll, halconcppxl.dll,
lib\%HALCONARCH%\halconxl.lib, halconcppxl.lib:
The corresponding libraries of HALCON XL (Windows).
lib/$HALCONARCH/libhalcon.so:
The HALCON library (Linux).
48 Creating Applications With HALCON/C++
lib/$HALCONARCH/libhalconcpp.so:
The HALCON/C++ library (Linux).
lib/$HALCONARCH/libhalconxl.so,libhalconcppxl.so:
The corresponding libraries of HALCON XL (Linux).
/Library/Frameworks/HALCONCpp.framework
The HALCON/C++ framework (macOS).
/Library/Frameworks/HALCONCppxl.framework
The corresponding framework of HALCON XL (macOS).
include\HProto.h:
External function declarations.
%HALCONEXAMPLES%\cpp\console\makefiles\makefile, makefile.win:
Example makefiles which can be used to compile the example programs (Linux/macOS and Windows, re-
spectively).
%HALCONEXAMPLES%\cpp\make.%HALCONARCH%, macros.mak, rules.mak:
Auxiliary makefiles included by the makefiles listed above.
%HALCONEXAMPLES%\cpp\console\source\
Directory containing the source files of the example programs.
%HALCONEXAMPLES%\cpp\console\vs2005\examples.sln:
Visual Studio 2005 solution containing projects for all examples; the projects themselves are placed in
subdirectories (Windows only).
%HALCONEXAMPLES%\cpp\console\bin\%HALCONARCH%\
Destination of the example programs when compiled and linked using the makefiles.
%HALCONEXAMPLES%\images\:
Images used by the example programs.
help\operators_*:
Files necessary for online information.
doc\pdf\:
Various manuals (in subdirectories).
error_handling.cpp demonstrates the C++ exception handling (see section 5.3 on page 37).
ia_callback.cpp shows the usage of the HALCON image acquisition callback functionality.
matching.cpp locates a chip on a board and measures the pins.
serialized_item.cpp shows how to use the serialization of HALCON objects and tuples in the C++ interface.
Additional examples for using HALCON/C++ can be found in the subdirectories mfc, motif and qt of
%HALCONEXAMPLES%.
7.3 Relevant Environment Variables 49
C++
section 1.4 on page 8, for more information.
The variable HALCONEXAMPLES indicates where the provided examples are installed.
If user-defined packages are used, the environment variable HALCONEXTENSIONS has to be set. HALCON will
look for possible extensions and their corresponding help files in the directories given in HALCONEXTENSIONS.
Two things are important in connection with the example programs: The default directory for the HALCON
operator ReadImage to look for images is %HALCONEXAMPLES%\images. If the images reside in different di-
rectories, the appropriate path must be set in ReadImage or the default image directory must be changed, using
SetSystem("image_dir","..."). This is also possible with the environment variable HALCONIMAGES. The
latter has to be set before starting the program.
The second remark concerns the output terminal under Linux. In the example programs, no host name
is passed to OpenWindow. Therefore, the window is opened on the machine that is specified in the envi-
ronment variable DISPLAY. If output on a different terminal is desired, this can be done either directly in
OpenWindow(...,"hostname",...) or by specifying a host name in DISPLAY.
#include "HalconCpp.h"
In order to create an application you must link the library halconcpp.lib to your program.
The example projects show the necessary Visual C++ project settings. Basically, you need to specify the correct
include path in the compiler settings, and the correct library path and libraries in the linker settings:
Compiler:
Include Directories: $(HALCONROOT)\include,$(HALCONROOT)\include\halconcpp
Linker:
Library Directories: $(HALCONROOT)\lib\$(HALCONARCH)
Additional Dependencies: halconcpp.lib
HALCON XL applications: If you want to use HALCON XL, you have to link the library halconcppxl.lib
instead.
Your own C++ programs that use HALCON operators must include the file HalconCpp.h, which contains all
user-relevant definitions of the HALCON system and the declarations necessary for the C++ interface. Do this by
adding the following command near the top of your C++ file:
#include "HalconCpp.h"
To specify the include path for the compiler on the command line, use the following syntax:
-I$HALCONROOT/include -I$HALCONROOT/include/halconcpp
To create an application, you have to link two libraries to your program: The library libhalconcpp.so contains
the various components of the HALCON/C++ interface. The library libhalcon.so is the HALCON library. To
specify the library path and the libraries for the linker, use the following syntax:
HALCON XL applications: If you want to use HALCON XL, you have to link the libraries libhalconcppxl.so
and libhalconxl.so instead.
Please take a look at the example makefiles for suitable settings. If you call gmake without further arguments, the
example application matching will be created. To create the other example applications (e.g., error_handling),
call
gmake error_handling
You can use the example makefiles not only to compile and link the example programs but also your own programs
(if placed in the subdirectory source). For example, to compile and link a source file called myprogram.cpp call
gmake myprogram
You can link the program to the HALCON XL libraries by adding XL=1 to the make command, for example
In order to link and run applications under Linux, you have to include the HALCON library path
$HALCONROOT/lib/$HALCONARCH in the system variable LD_LIBRARY_PATH.
7.7 macOS 51
Your own C++ programs that use HALCON operators must include the file HalconCpp.h, which contains all
user-relevant definitions of the HALCON system and the declarations necessary for the C++ interface. Do this by
adding the following command near the top of your C++ file:
#include <HALCONCpp/HalconCpp.h>
Using this syntax, the compiler looks for HalconCpp.h in the HALCONCpp framework. For HALCON XL the
include statement has to be adapted:
C++
#include <HALCONCppxl/HalconCpp.h>
To create an application, you have to link the framework HALCONCpp to your program.
HALCON XL applications: If you want to use HALCON XL, you have to link the library framework
HALCONCppxl instead.
Please take a look at the example Xcode projects under /Users/Shared/Library/Application
Support/HALCON-19.05/examples/cpp for suitable project settings.
52 Creating Applications With HALCON/C++
Typical Image Processing Problems 53
Chapter 8
C++
Typical Image Processing Problems
This chapter shows the power the HALCON system offers to find solutions for image processing problems. Some
typical problems are introduced together with sample solutions.
HImage Image("file_xyz");
HRegion Threshold = Image.Threshold(0,120);
HRegion ConnectedRegions = Threshold.Connection();
HRegion ResultingRegions =
ConnectedRegions.SelectShape("area","and",10,100000);
HImage Image("file_xyz");
HImage Sobel = Image.SobelAmp("sum_abs",3);
HRegion Max = Sobel.Threshold(30,255);
HRegion Edges = Max.Skeleton();
Some notes:
• Before applying the sobel operator it might be useful first to apply a low-pass filter to the image in order to
suppress noise.
• Besides the sobel operator you can also use filters like EdgesImage, PrewittAmp, RobinsonAmp,
KirschAmp, Roberts, BandpassImage, or Laplace.
• The threshold (in our case 30) must be selected appropriately depending on data.
• The resulting regions are thinned by a Skeleton operator. This leads to regions with a pixel width of 1.
54 Typical Image Processing Problems
HImage Image("file_xyz");
HImage Mean = Image.MeanImage(11,11);
HRegion Threshold = Image.DynThreshold(Mean,5,"light");
Texture transformation is useful in order to obtain specific frequency bands in an image. Thus, a texture filter
detects specific structures in an image. In the following case this structure depends on the chosen filter; 16 are
available for the operator TextureLaws.
HImage Image("file_xyz");
HImage TT = Image.TextureLaws("ee",2,5);
HImage Mean = TT.MeanImage(71,71);
HRegion Reg = Mean.Threshold(30,255);
• The mean filter MeanImage is applied with a large mask size in order to smooth the “frequency” image.
• You can also apply several texture transformations and combine the results by using the operators AddImage
and MultImage.
The morphological operator Opening eliminates small objects and smoothes the contours of regions.
...
segmentation(Image,&Seg);
HRegion Circle(100,100,3.5);
HRegion Res = Seg.Opening(Circle);
• The term segmentation() is an arbitrary segmentation step that results in an array of regions (Seg).
• The size of the mask (in this case the radius is 3.5) determines the size of the resulting objects.
• You can choose an arbitrary mask shape.
Part III
Chapter 9
Introducing HALCON/.NET
This chapter introduces you to HALCON/.NET. Chapter 10 on page 59 shows how to use it to create .NET appli-
.NET
cations, chapter 11 on page 79 contains additional information.
What is HALCON/.NET?
HALCON/.NET is HALCON’s interface to .NET programming languages, e.g., C# or Visual Basic .NET. It pro-
vides you with a set of .NET classes and controls.
Platform Independency
HALCON/.NET is highly platform-independent: It is written in C# but can be used in any .NET language. Like
.NET in general, it can be used under Windows and Linux, on 32-bit and 64-bit systems.
What’s more, you can not only use it on all these platforms, but you can run an application created on one of them
on the other ones without needing to recompile. This is possible because applications written in .NET languages
are stored in a platform-independent intermediate language, which is then compiled by the so-called common
language runtime into platform-specific code.
HDevEngine/.NET
By combining HALCON/.NET and HDevEngine/.NET, you can execute HDevelop programs and procedures from
a .NET application. For more information, please refer to part V on page 115.
Chapter 10
.NET
This chapter shows you how to create applications with HALCON/.NET. The examples are given in C#, using
Visual Studio .NET under Windows as development environment. If programming constructs or activities differ in
Visual Basic .NET or managed C++, this is noted at the first occurrence. How to create applications under Linux
using Mono is described in section 11.2 on page 81. The provided online help is listed in section 10.5.1 on page
65.
This chapter describes how to
• add HALCON/.NET to an application (section 10.2 on page 61)
• add and customize a window control for visualization (see section 10.3 on page 62, and section 10.4 on page
63)
• use HALCON/.NET classes to call HALCON operators (section 10.5 on page 65)
• work with tuples (section 10.6 on page 69)
• work with vectors (section 10.7 on page 74)
• visualize images and results (section 10.8 on page 75)
• perform error handling (section 10.9 on page 76)
• deploy an application (section 10.10 on page 76)
• use a newer release of HALCON/.NET (section 10.11 on page 77)
Many of the code examples stem from the example Matching, which is provided in C# (%HALCONEXAMPLES%\
c#), Visual Basic .NET (%HALCONEXAMPLES%\vb.net), and managed C++ (%HALCONEXAMPLES%\cpp.net). An
overview of the provided example applications can be found in section 11.1 on page 79.
But before explaining how to create applications, we must take a brief look under the hood of .NET: at the depen-
dency of applications on the .NET Framework.
Chapter 9 on page 57 emphasized the platform-independency of .NET applications. However, applications are not
completely independent: They depend on the version of the .NET Framework they have been created with, i.e., the
underlying SDK, development environment, etc.
60 Creating Applications With HALCON/.NET
Table 10.1 on page 60 shows which version of Visual Studio is based on which version of the .NET Framework.
.NET Framework 3.5 added many new features compared to older versions, in particular WPF support. In order
to support these features without dropping support for .NET Framework 2.0 the HALCON/.NET assembly is
provided in two variants:
Newer versions of the .NET Framework provide backwards compatibility, e.g., .NET Framework 4.0 can use
assemblies from 3.5. However, note that all applications that use WPF support must use the .NET Framework
3.5 version of HALCON/.NET. All other applications may use both versions of HALCON/.NET. Please note that
client profiles are not supported.
Mono at the time of writing implements most features of .NET Framework 2.0 but not WPF. Therefore it is
recommended to use the dotnet20 version of HALCON/.NET for the use with Mono.
Furthermore, the example applications (see section 11.1 on page 79 for an overview) are provided in a modular
directory structure:
. source: contains shared source files
. vs2005: contains the project files for Visual Studio 2005 or higher
. vs2008: contains the project files for Visual Studio 2008 or higher
. vs2010: contains the project files for Visual Studio 2010 or higher
. makefiles: contains makefiles for compiling the applications from the command line, in particular using
Mono (see section 11.2 on page 81 for more information)
Thus, to open an example in Visual Studio 2005 or higher, you open the corresponding project file in the subdirec-
tory vs2005. Note that only some examples have special support for Visual Studio 2008 (or Visual Studio 2010)
and therefore have a subdirectory vs2008 (or vs2010). If this is not the case, open the project file in vs2005.
Note that when opening a project from an older version of Visual Studio, the project will be upgraded automatically
(with only minor changes to the project file). Table 10.2 on page 61 lists more generally whether a project created
with one version of Visual Studio can be opened with another.
Please note that the provided examples reference the HALCON/.NET assembly using a local path. Therefore,
when you copy an example to another location, the assembly will not be found, which is signalled in the Solution
Explorer by a broken reference. In such a case, delete the reference and add the correct one as described in
section 10.2.2 on page 61.
If you are copying examples to locations other than on a local disk, please note that you must adapt the .NET
Framework Configuration as described in section 11.4.1 on page 83, otherwise you get a warning upon loading the
project and a run-time error upon executing it.
10.2 Adding HALCON/.NET to an Application 61
You add HALCON/.NET to an application with the following steps: For the first application:
• customize Visual Studio’s toolbox (section 10.2.1 on page 61)
For each application:
.NET
• add a reference to HALCON/.NET (section 10.2.2 on page 61) and
• specify the namespace (section 10.2.3 on page 62)
In fact, the HALCON/.NET assembly provides not only a class library but also one control:
HSmartWindowControl (or HSmartWindowControlWPF), which contains a HALCON graphics window for vi-
sualizing images and results.
The older control HWindowControl is still available for backwards compatibility, but it is highly recommended
not to use this control for new projects (see section 10.3 on page 62 for information about the differences).
You can add these controls to Visual Studio’s toolbox by performing the following steps (note that the exact menu
names are slightly different in different versions of Visual Studio!):
• Right-click on the toolbox and select Choose Items (Customize Toolbox in previous versions of Visual
Studio). This will open a dialog displaying all available .NET Framework components in a tab.
• Click on Browse, navigate to the directory %HALCONROOT%\bin\dotnet20 (Visual Studio 2005) or
%HALCONROOT%\bin\dotnet35 (Visual Studio 2008 or higher) and select halcondotnet.dll.
• Then, the icon of HSmartWindowControl and the older HWindowControl appear in the toolbox.
HALCON XL applications: When developing an application with HALCON XL, you must select
halcondotnetxl.dll instead of halcondotnet.dll. In the toolbox, the control appears with the same name but
with a different icon. You can add both HALCON versions to the toolbox, but only one of them to an application.
In many applications you will use at least one instance of HSmartWindowControl to visualize results. By adding
the control to the form (as described in section 10.4 on page 63), you automatically create a reference to the
assembly halcondotnet.dll.
If you do not want to use HSmartWindowControl, you add a reference as follows:
• Right-click References in the Solution Explorer and select Add Reference.
• Click on Browse, navigate to the subdirectory %HALCONROOT%\bin\dotnet20 (Visual Studio 2005) or
%HALCONROOT%\bin\dotnet35 (Visual Studio 2008) and select the assembly halcondotnet.dll.
HALCON XL applications: When developing an application with HALCON XL, you must select
halcondotnetxl.dll instead of halcondotnet.dll. If you already added a reference to the HALCON version,
simply delete that reference and add one to halcondotnetxl.dll.
62 Creating Applications With HALCON/.NET
To be able to use the HALCON/.NET classes without prefixing them with their namespace, we recommend to
specify this namespace at the beginning of each source file (see, e.g., the example MatchingForm.cs)) by adding
the following line:
using HalconDotNet;
Visual Basic .NET applications: The corresponding Visual Basic .NET code is (see, e.g., MatchingForm.vb):
Imports HalconDotNet
C++ applications: The corresponding managed C++ code is (see, e.g., MatchingForm.h):
• It is used like any other control (e.g., it can be embedded in TabControls or ScrollViewers, or overlaid
with other controls).
• Predefined mouse interaction is provided (moving of the window contents and zooming using the mouse
wheel). The view can be reset by double-clicking the window.
• The control automatically rescales without flickering.
In addition, you need to transform the mouse coordinates, so that they are relative to the upper left corner of the
HSmartWindowControl.
Using the smart window control, the following events are triggered and can be reacted to:
• Click
• GotFocus, LostFocus
10.4 Adding and Customizing HSmartWindowControl for the Visualization 63
Please note that not all operators can be used with the smart window control. For example, draw_* operators and
get_mbutton(_subpix) or get_mposition(_subpix) are not supported with this window control. Drawing
objects have to be used instead.
In the following sections, the term HSmartWindowControl will be used for simplicity. Read it as
HSmartWindowControlWPF if your project is based on WPF. The same applies to the older HWindowControl
correspondingly.
.NET
In most applications you want to visualize at least some results. Then, you start by adding HSmartWindowControl
to the form by double-clicking the corresponding icon in the toolbar. An empty (black) window appears (see
figure 10.1 on page 64).
HALCON XL applications:
If you already added the HALCON version of the control, but now want to use HALCON XL, simply delete the
reference to halcondotnet.dll in the Solution Explorer and add a reference to halcondotnetxl.dll instead
(also see section 10.2.2 on page 61).
If you want to fit an image automatically without the need to double click, you can use the operator SetPart:
Alternatively, you can call SetFullImagePart to resize the image to the size of the window control:
WindowControl.SetFullImagePart(null);
The properties specific to this control are listed below in alphabetical order. They can be adapted in the Properties
window (see figure 10.1 on page 64). Note that some properties are only available for HSmartWindowControlWPF
elements. All properties of the HSmartWindowControlWPF support data binding.
Do not modify the “Brush” properties in Visual Studio. They are disabled for HSmartWindowControlWPF to
prevent undesired side-effects.
HColor
Specifies the color of HRegion and HXLDCont objects.
HColored
Specifies the colors for displaying multiple HRegion or HXLDCont objects in different colors.
HDisableAutoResize
If set to true, images are not automatically scaled when they are displayed.
HDisplayCurrentObject
Displays the assigned HImage or HObject.
HDoubleClickToFitContent
If set to true (the default), double clicking resizes the content of the HSmartWindowControl to fit the size
of the control. If the HKeepAspectRatio is also set to true, the contents are rescaled so that the aspect ratio
is maintained.
HDraw
Specifies the fill mode of HRegion objects. If HDraw is set to ’fill’, output regions are filled, if set to
’margin’, only contours are displayed.
64 Creating Applications With HALCON/.NET
HDrawingObjectsModifier
Specifies the modifier key to interact with drawing objects. If a modifier key is set, the user can only interact
with drawing objects while keeping the modifier key pressed. This is especially useful when interacting with
XLD drawing objects. By default, it is set to None. Other possible values are Alt, Ctrl, or Shift.
HFont
Specifies the font for displaying messages in the HSmartWindowControlWPF.
HImagePart
Specifies the image part of the corresponding HALCON window. Note that the part is specified with the
values X, Y, Width, and Height, whereas the corresponding operator SetPart expects the four corner
points. Note that you can modify the displayed part in your application at any time, e.g., to display a zoomed
part of the image. See section 10.8 on page 75 for more information about actually visualizing results.
HKeepAspectRatio
If set to true (the default), the content of the HSmartWindowControl keeps its aspect ratio when the control
is resized or zoomed. The aspect ratio is the quotient Width/Height set at design time with HImagePart.
HLineStyle
Specifies the contour pattern of HRegion and HXLDCont objects.
HLineWidth
Specifies the contour thickness of HRegion and HXLDCont objects.
HMoveContent
If set to true (the default), the contents of the HALCON window can be dragged using the mouse.
HZoomContent
Specifies the behavior of the mouse wheel. If set to WheelForwardZoomsIn (the default), the contents
of the HALCON window is zoomed in and out when moving the mouse wheel forwards and backwards,
respectively. Setting the property to WheelBackwardZoomsIn reverses the behavior. If set to Off, zooming
using the mouse wheel is disabled.
HZoomFactor
Specifies the step size when zooming with the mouse wheel. The default is 1.41. Values must be greater
than 1 and less or equal to 100. A higher value leads to faster zooming.
The HSmartWindowControlWPF can be used to implement the Model-View-Viewmodel (MVVM) pattern, as all
properties of the control support data binding. By adding objects to the Items collection or setting the ItemsSource
10.5 Using HALCON/.NET Classes 65
property you can control what the control should display, also in pure XAML code. The following example
illustrates how to show an image, color a region in “magenta”, and display a text message:
<HalconDotNet:HSmartWindowControlWPF HDraw="fill">
<!--Iconic items can be added using HIconicDisplayObjectWPFs-->
<HalconDotNet:HIconicDisplayObjectWPF IconicObject="{Binding DisplayImage}"/>
<!--Also with individual drawing properties-->
<HalconDotNet:HIconicDisplayObjectWPF IconicObject="{Binding DisplayRegion}"/>
HDraw="margin" HColor="magenta"/>
<!--Messages can be displayed using HMessageDisplayObjectWPFs-->
<HalconDotNet:HMessageDisplayObjectWPF HMessageText="{Binding ImageName}"/>
</HalconDotNet:HSmartWindowControlWPF>
Note that DisplayImage, DisplayRegion and ImageName have to exist in the DataContext of the
HSmartWindowControlWPF.
.NET
In HALCON/.NET, you call HALCON operators via instances of classes. The following code, e.g., grabs the first
image of an image sequence and displays it in the graphics window of HSmartWindowControl:
Window = WindowControl.HalconWindow;
Framegrabber = new HFramegrabber("File", 1, 1, 0, 0, 0, 0, "default",
-1, "default", -1, "default",
"board/board.seq", "default", 1, -1);
Img = Framegrabber.GrabImage();
Img.GetImagePointer1(out ImgType, out ImgWidth, out ImgHeight);
Window.SetPart(0, 0, ImgHeight - 1, ImgWidth - 1);
Img.DispObj(Window);
The operator GrabImage is called via an instance of HFramegrabber. As an experienced HALCON user you will
perhaps have identified the constructor of HFramegrabber as a call to the operator OpenFramegrabber.
Below, we take a closer look at:
• how to call operators via HALCON/.NET’s classes (section 10.5.2 on page 66)
• construction, initialization, and destruction of class instances (section 10.5.3 on page 66)
• overloads of operator calls (section 10.5.4 on page 69)
But first, we give you an overview of the provided online help.
The main source of information about HALCON/.NET operators and classes is the reference manual, which
is available as HTML and PDF version (note that the latter is only provided in HDevelop syntax). Un-
der Windows, you can open both versions via the Start Menu. Under Linux, open index.html in the di-
rectory $HALCONROOT/doc/html/reference/operators, and reference_hdevelop.pdf in the directory
$HALCONROOT/doc/pdf/reference, respectively. You can access them also via HDevelop’s Help Browser.
The Reference Manual describes the functionality of each HALCON operator and its signatures, i.e., via which
classes it can be called with which parameters. Furthermore, it gives an overview of the provided classes (which
does not list all methods, however, only the HALCON operators).
Online help is also available in Visual Studio:
• When you type a dot (.) after the name of a class or class instance, the automatic context help (IntelliSense)
lists all available methods.
66 Creating Applications With HALCON/.NET
• Similarly, when you type the name of a method, its signature(s) is (are) listed.
• For parameters of HALCON operators, a short description and the the so-called default value is shown. Note
that HALCON operators do not have “real” default parameter values, i.e., you cannot leave out a parameter
and let HALCON use a default value. Instead, the listed default value is a typical value chosen for the
parameter.
• The Object Browser lists all HALCON/.NET classes with their methods, including a short description.
Via which classes you can call a HALCON operator is listed in the reference manual. Figure 10.2 on page 66
shows the corresponding part of the description of the operator GrabImage:
Figure 10.2: The head and parts of the parameter section of the reference manual entry for GrabImage.
As you can see, the operator can be called via three classes: HOperatorSet, HImage, and HFramegrabber. The
first variant, via HOperatorSet, is mainly used for the export of HDevelop programs (see section 11.3 on page
82).
For normal applications, we recommend to call operators via the other classes, in the example HImage and
HFramegrabber as in the following code example:
HImage Image1;
HImage Image4 = new HImage();
HFramegrabber Framegrabber =
new HFramegrabber("File", 1, 1, 0, 0, 0, 0, "default", -1,
"default", -1, "default", "board/board.seq", "default", -1, -1);
Image1 = Framegrabber.GrabImage();
HImage Image3 = null;
Note that in the call via HFramegrabber the grabbed image is the return value of the method, whereas the call via
HImage has no return value and the calling class instance is modified instead. Usually, calling class instances are
not modified by an operator call - with the exception of “constructor-like” operator calls as in the example above.
Some operators like CountSeconds are available as class methods, i.e., you can call them directly via the class
and do not need an instance:
double S1, S2;
S1 = HSystem.CountSeconds();
In the reference manual, these operator calls start with the keyword static:
During the lifecycle of an object, i.e., from declaration to finalization, different amounts of memory are allocated
and released.
The following declaration just declares a variable of the class HImage that does not yet refer to any object:
10.5 Using HALCON/.NET Classes 67
Figure 10.3: The head of the reference manual entry for CountSeconds.
HImage Image1;
In this state, you cannot use the variable to call operators; depending on the programming language, you might not
even be able to use it as an output parameter (e.g., in Visual Basic 2005). However, you can assign image objects
to the variable, e.g., from the return value of an operator:
Image1 = Framegrabber.GrabImage();
.NET
You can also initialize a variable when declaring it:
Note that you can check the initialization state of a class instance with the method IsInitialized.
10.5.3.1 Constructors
In contrast, the following declaration calls the “empty” constructor of the class HImage, which creates an unititial-
ized class instance:
This class instance can be used to call “constructor-like” operators like GrabImage, which initializes it with a
grabbed image:
Image4.GrabImage(Framegrabber);
Besides the empty constructor, most HALCON/.NET classes provide one or more constructors that initialize the
created object based on HALCON operators. For example, HImage provides a constructor based on the operator
ReadImage:
You can check which constructors are provided via the online help:
• The reference manual pages for the classes don’t list the constructors themselves but the operators they are
based on. The constructor then has the same signature as the operator (minus the output parameter that
corresponds to the class, of course).
• The online help in Visual Studio lists the constructors but not the operators they are based on.
10.5.3.2 Finalizers
The main idea behind memory management in .NET is that the programmer does not worry about it and lets the
garbage collector delete all objects that are not used anymore. HALCON/.NET fully complies to this philosophy
by providing corresponding finalizers for all classes so that even unmanaged resources, e.g., a connection to an
image acquisition device, are deleted correctly and automatically.
68 Creating Applications With HALCON/.NET
Figure 10.4: The head of the reference manual entry for CloseFramegrabber.
For most classes, the finalizer automatically calls suitable operators like CloseFramegrabber to free resources.
Which operator is called is listed in the reference manual page of a class (see, e.g., the entry for HFramegrabber).
This operator cannot be called via the class, as can be seen in the corresponding reference manual entry:
You do not even need to call such an operator if you, e.g., want to re-open the connection with different parameters,
because this is done automatically.
! Please don’t call Close or Clear operators via HOperatorSet when using the normal classes like
HFramegrabber.
As remarked above, the .NET philosophy is to let the garbage collector remove unused objects. However, because
the garbage collector deletes unused objects only from time to time, the used memory increases in the meantime.
Even more important is that, to the garbage collector, HALCON’s iconic variables (images, regions, ...) seem to
be rather “small”, because they only contain a reference to the (in many cases rather large) iconic objects in the
database. Thus, the garbage collector may not free such variables even if they are not used anymore.
Therefore, you might need to force the removal of (unused) objects. There are two ways to do this:
• Call the garbage collector manually. In the example Matching, this is done after each processing run in the
timer event:
private void Timer_Tick(object sender, System.EventArgs e)
{
Action();
GC.Collect();
GC.WaitForPendingFinalizers();
}
C++ applications: The code for calling the Garbage Collector in a managed C++ application is
GC::Collect();
GC::WaitForPendingFinalizers();
Besides reducing memory consumption, another reason to manually dispose of objects is to free resources, e.g.,
close a connection to an image acquisition device or a serial interface.
HTuple instances that contain handles also need to be disposed if the referenced resource is to be released in a
deterministic way.
Please note that HALCON operators always create a new object instance for output parameters and return values
(but not in the “constructor-like” operator calls that modify the calling instance). If the variable was already
initialized, its old content (and the memory allocated for it) still exists until the garbage collector removes it. If
you want to remove it manually, you must call Dispose before assigning an object to it.
10.6 Working with Tuples 69
Please note that operator overloads are not available in Visual Basic .NET!
The following tables list the currently available operator overloads. !
.NET
- (scalar) subtracts a constant gray value offset
∗ (scalar) scales an image by the specified factor
/ (scalar) scales an image by the specified divisor
>= (image) segments an image using dynamic threshold
<= (image) segments an image using dynamic threshold
>= (scalar) segments an image using constant threshold
<= (scalar) segments an image using constant threshold
& (region) reduces the domain of an image
ically returns the area and center coordinates of all passed regions. Analogously, if you call GenRectangle1 with
multiple values for the rectangle coordinates, it creates multiple regions.
The following sections provide more detailed information about
• how to find out whether an operator can be called in tuple mode (section 10.6.1 on page 70)
• tuples of iconic objects (section 10.6.2 on page 71)
• tuple of control values (section 10.6.3 on page 71)
You can check whether an operator also works with tuples in the reference manual. Below, e.g., we show the
relevant parts of the operators AreaCenter and GenRectangle1.
As you see, the iconic classes like HRegion automatically handle multiple values; whether such a parameter accepts
/ returns multiple values is not visible from the signature but only in the parameter section: Here, an appended
(-array) (in the example: HRegion(-array)) signals that the parameter can contain a single or multiple values.
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)
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)
In contrast, control parameters show by their data type whether they contain a single or multiple values: In the first
case, they use basic data types like double, in the second case the HALCON/.NET class HTuple. Thus, you can
call GenRectangle1 via HRegion in two ways, either by passing doubles or HTuples (here using the constructor
form):
Below, we provide additional information about iconic tuples (section 10.6.2 on page 71) and control tuples (sec-
tion 10.6.3 on page 71).
.NET
and then access elements either with the HALCON operator SelectObj or (when using C#) with the operator []:
To process all elements of a tuple, you first query its length via the property Length:
Note that you get an exception if you try to read a non-existing tuple element or if you try to assign an element to
a variable with a different type without cast.
The class HTuple provides many different constructors (see the Visual Studio’s Object Browser for a list). The
following line creates an int tuple with a single value:
You can also pass multiple values to a constructor. Note that when mixing double and int values as in the
following line, a double tuple is created:
In contrast, when the list of values also contains a string, a mixed type tuple is created, in which the second
value is stored as an int:
The type of a tuple or of a tuple element can be queried via its property Type:
You can also append elements to a tuple by writing into a non-existing element:
Tuple3[2] = 3;
The class HTuple provides many implicit cast methods so that you can intuitively use the basic data types in most
places. For example, the line
automatically casts the element, which is in fact an instance of the class HTupleElement, into a double.
Similarly, basic types are automatically casted into instances of HTuple. The drawback of the casts is that the
compiler often cannot decide whether you want to use the simple or the tuple version of an operator and issues
a corresponding error. For example, if you used the following line, the values can either be casted from int to
double or to HTuple:
You can resolve the ambiguity very simply by appending .0 to the first parameter:
10.6 Working with Tuples 73
The example Matching contains two other cases of ambiguities, both arising because basic-type and HTuple
parameters are mixed in the same call. In the first, the ambiguity is solved by explicitly casting the double
parameters into instances of HTuple:
In the second case, the instances of HTuple (which only contain single values) are explicitly casted into doubles
by using the property D, which returns the value of the first element as a double (actually, it is a shortcut for
tuple[0].D):
.NET
HTuple Rect1RowCheck, Rect1ColCheck;
Rectangle1.GenRectangle2(Rect1RowCheck.D, Rect1ColCheck.D,
RectPhi + AngleCheck.D,
RectLength1, RectLength2);
With similar properties, you can cast tuple elements into the other basic types. Note, however, that you get an
exception if you try to cast an element into a “wrong” type.
In contrast to input parameters, output parameters are not automatically casted. Sometimes, this leads to unex-
pected results. In the following code, e.g., doubles are used for the output parameters and the return value in a
call to AreaCenter with a tuple of regions:
Consequently, only the area and the center of the first region are returned. The same happens if you assign the
return value to an HTuple, but still pass doubles for the output parameters:
In contrast, if you pass HTuples for the output parameters and assign the return value to a double, the operator
returns the center coordinates of all regions but only the area of the first region:
HALCON provides many operators for processing tuples. In the reference manual, these operators can be found in
the chapter “Tuple”. An overview of these operators is given in the HDevelop User’s Guide in chapter 8 on page
271. Note that instead of the operator name, the name of the corresponding HDevelop function is used, which
omits the Tuple and uses lowercase characters, e.g., rad instead of TupleRad.
For the basic arithmetic operations, HALCON/.NET provides operator overloads. For example, the operator +
automatically calls the HALCON operator TupleAdd.
74 Creating Applications With HALCON/.NET
HALCON/.NET provides the class HVector for the use of variables of type ’vector’ of the HDevelop language,
i.e., containers that can hold an arbitrary number of elements of the identical data type (i.e., tuple, iconic object,
or vector) and dimension. The type of a vector, i.e., its dimension and the type of its elements is defined when
initializing the vector instance and cannot be changed during its lifetime. A one-dimensional vector may be a
vector of tuples or a vector of iconic objects. A two-dimensional vector may be a vector of vectors of tuples or
a vector of vector of iconic objects, and so on. Instances of vectors can be created from the following derived
classes:
In the following some basic information about the use of vectors in HALCON/.NET is given when using C#.
Construction of Vectors
As already mentioned, an instance of a vector can only be created from HObjectVector or HTupleVector.
The vector type cannot be changed after its construction. Thus, a tuple cannot be assigned to a vector of iconic
objects and vice versa.
You may also create a multi-dimensional vector, i.e., a vector of vectors and so on, by specifying the number of
dimensions in brackets. However, the dimension of a vector has to remain constant within the program and cannot
be changed. The following code line describes how to create a vector of two dimensions, i.e., a vector of vectors
of tuples.
Note that the vectors created by these calls are still empty. How to access and set vector elements is described
below.
The specified index in square brackets defines the element to be accessed. If a subelement of a multi-dimensional
vector is to be accessed, you have to use the indices of the corresponding subvector and its subelement instead.
When setting a vector element the expression for accessing a vector element is needed as reference to the HObject
or HTuple, respectively. The value to be set must be specified on the right side of the assignment.
10.8 Visualization 75
In the example code the image is copied and set as the first element of vectorObj. The tuple is also copied but set
as the second vector element of vectorTup.
Setting a subelement of a multi-dimensional vector can be done analogously to setting an element in a one-
dimensional vector when using the corresponding indices of the subvector(s) and its subelement.
If a non-existing vector element is set or accessed, the vector is automatically enlarged and filled with empty
elements if necessary.
Destruction of Vectors
.NET
If a HObjectVector or HTupleVector is not needed anymore for further processing its contents should be cleared
with .Dispose().
vectorObj.Dispose();
Additional Information
In addition to accessing and setting the elements of vectors, HObjectVector and HTupleVector provide further
functionalities for the use of HALCON vectors such as inserting and removing vector elements or concatenation
of vectors. For more details on the provided vector functionality you may use the automatic context help in Visual
Studio, IntelliSense.
10.8 Visualization
In most applications you will use an instance of HSmartWindowControl for the display of images of results. How
to configure this control is described in section 10.4 on page 63. The actual display operators, however, do not use
the control but the HALCON graphics window (class HWindow) encapsulated inside. You can access the graphics
window via the property HalconWindow of HSmartWindowControl:
In the code above, the variable for the instance of HWindow was declared globally and initialized in the event Load
of the form.
You can configure the display parameters like pen color or line width with the operators in the reference manual
chapter “Graphics . Parameters”:
Window.SetDraw("margin");
Window.SetLineWidth(3);
Images and other iconic objects are displayed with the operator DispObj, which can be called via the object to
display with the window as parameter or vice versa:
Img.DispObj(Window);
76 Creating Applications With HALCON/.NET
More display operators, e.g., to display lines or circles, can be found in the reference manual chapter “Graphics .
Output”.
Instead of (or in addition to) using HSmartWindowControl, you can also open a HALCON graphics windows
directly with the operator OpenWindow:
In the code above, the window was opened “free-floating” on the display. You can also open it within another GUI
element by passing its handle in the parameter fatherWindow.
Before displaying anything in the graphics window, you should set the image part to display with the operator
SetPart. In the example code below, the opened window is used to display a zoomed part of the image:
More information about visualization in general can be found in the Solution Guide I, chapter 20 on page 247.
Note that in this manual, the HDevelop version of the display operators is used, i.e., with the prefix dev_, e.g.,
dev_open_window instead of OpenWindow.
The .NET programming languages each offer a mechanism for error handling. In C# and managed C++, you use
try...catch blocks. Within this standard mechanism, HALCON/.NET offers its special exceptions:
• HOperatorException is raised when an error occurs within a HALCON operator
• HTupleAccessException is raised when an error occurs upon accessing a HALCON tuple
The following code shows how to catch the error that occurs when the operator ReadImage is called with a wrong
image file name. Then, a message box is shown that displays the error code in the caption and the HALCON error
message:
HImage Image;
try
{
Image = new HImage("unknown");
}
catch (HOperatorException exception)
{
MessageBox.Show(exception.Message, "HALCON error # " + exception.GetErrorCode());
}
All HALCON error codes and their corresponding error messages are summarized in the Extension Package Pro-
grammer’s Manual, appendix A on page 103.
The HSmartWindowControl and HSmartWindowControlWPF provide the event HErrorNotify. This event al-
lows the user to react to errors that take place internally within the control, but can have external causes, like for
example an unplugged dongle or a missing license file.
By default, .NET applications use local assemblies. For HALCON/.NET applications, this means that the HAL-
CON/.NET assembly halcondotnet.dll is automatically copied to the directory of the application’s executable
(e.g., bin\Release). To deploy an application on another computer, you therefore simply copy the content of
this directory. Because of .NET’s platform independency, this computer can also run under a different operating
system than the development computer.
10.11 Using a Newer HALCON/.NET Release 77
Of course, the .NET Framework and HALCON must be installed on the destination computer as well, and the
environment variables PATH and HALCONARCH must be set correctly (see the Installation Guide, section A.2 on
page 45).
Note that you can also install the HALCON/.NET assembly in the so-called global assembly cache. Then, it is not
necessary to copy it with each application. See the .NET Framework documentation for details about this method.
Please note that applications that use HALCON/.NET have local copies of the corresponding assemblies. After
installing a newer release of HALCON, these applications would therefore still use their old HALCON assemblies.
In order to benefit from the changes in the HALCON/.NET interface as well, you must either replace the assemblies
manually or re-compile the projects.
If you replace the assemblies manually, you must furthermore map the application’s expected assembly version to
the new version. For this, copy the file bin\dotnet20\app.config or bin\dotnet35\app.config (identical
files) into the directory of the application and rename it to <application_name>.exe.config.
.NET
Another application of the configuration file is the case that a Visual Studio project references an assembly based
on HALCON that expects another maintenance release of HALCON. In this case, you must add app.config to
the project and re-compile it.
78 Creating Applications With HALCON/.NET
Additional Information 79
Chapter 11
Additional Information
This chapter provides additional information for developing applications with HALCON/.NET:
.NET
• Section 11.1 on page 79 gives an overview of the available example applications.
• Section 11.2 on page 81 explains how to use HALCON/.NET applications under Linux using Mono.
• Section 11.3 on page 82 shows how to use HDevelop programs or procedures in your .NET application.
• Section 11.4 on page 83 contains miscellaneous information.
11.1.1 C#
11.1.3 C++
11.2.1 Restrictions
Please note the following restrictions when developing or using HALCON/.NET applications via Mono:
• Mono supports Windows Forms but does not claim to implement the full functionality (yet). This has to be
.NET
kept in mind when developing applications under Windows and compiling or deploying them under Linux.
• HWindowControl is not yet initialized in the event Load of a form, due to a different initializa-
tion order of X Window widgets. Please place initialization and similar code in the event han-
dler of HSmartWindowControl’s (or HWindowControl’s) event HInitWindow (see e.g. the example
BarCodeReading):
• When using HALCON under Mono, only ASCII characters in the range 0-127 may be passed in string
parameter between application and HALCON library, unless it is known in advance that the data within
the HALCON library actually represents valid UTF-8. The reason is that Mono only supports marshalling
to/from UTF-8 when calling into native libraries. For example, the call
HOperatorSet.TupleChr(128, out t)
will fail with an exception on Mono, as the one-byte string containing only the value of 128 is not valid
UTF-8 and cannot be marshalled into the output string.
Because of HALCON/.NET’s platform independency, you can copy an application created under Windows to a
Linux computer and simply start it there - provided that Mono and HALCON are installed on the destination
computer (see section 10.10 on page 76 for more information).
Most of the HALCON/.NET examples provide a set of makefiles in the subdirectory makefiles to let you com-
pile them under Linux (see section 11.1 on page 79 for a list of the examples that support Linux). To start the
compilation, simply type
gmake
<configuration>
<dllmap dll="halcon"
target="/opt/halcon/lib/x64-linux/libhalcon.so"/>
</configuration>
Figure 11.1: Example for a configuration file with HALCON being installed in the directory /opt/halcon.
gmake XL=1
In some cases, Mono may not find the native HALCON library libhalcon.so, which should be resolved via the
environment variable LD_LIBRARY_PATH and issue a corresponding error. You can create configuration files for
the HALCON/.NET (and HDevEngine/.NET) assembly, which explicitly specify the path to the HALCON library
(see figure 11.1 on page 82 for an example), by calling
gmake config
If you want to create a configuration file for only one of the assemblies, use the make commands config_halcon
and config_engine.
Note that you can also use xbuild (Mono’s implementation of msbuild) with the project files.
.NET
Figure 11.3: The template form for exported code.
The exported code does not use the classes like HImage described in the previous chapter. Instead, all operators
are called via the special class HOperatorSet. Iconic parameters are passed via the class HObject (which is the
base class of HImage, HRegion, and HXLD), control parameters via the class HTuple.
You can combine the exported code easily with “normal” HALCON/.NET code because iconic classes provide
constructors that initialize them with instances of HObject. Furthermore, iconic classes can be passed to methods
that expect an HObject.
11.4 Miscellaneous
If you want to develop .NET application (independent on the used HALCON interface) in other locations than on a
local disk, you must configure the .NET security policy to allow executing code from your desired project location.
Otherwise, you get a warning upon creating or loading the project that the location is not trusted and a run-time
error upon executing it.
You can configure the .NET security policy in two ways:
Figure 11.4: Error message upon running a template without exported code.
84 Additional Information
Note that you need administrator privileges to change the .NET security policy.
Further note that to create .NET applications in Visual Studio, you must be a member of the group Debugger
User.
For performance reasons, HALCON/.NET suppresses unmanaged code security when making calls into the native
HALCON library. Should your machine vision application run in an environment which allows remote access, you
might wish to explicitly check permissions for code calling into your application or library.
Part IV
Chapter 12
Introducing HALCON/C
HALCON/C is the interface of the image analysis system HALCON to the programming language C. Together
with the HALCON library, it allows to use the image processing power of HALCON inside C programs.
This part is organized as follows: We start with a first example program to show you how programming with
HALCON/C looks like. Chapter 13 on page 89 introduces the different parameter classes of HALCON operators.
We will explain the use of HALCON tuples (section 13.2.4 on page 92) for supplying operators with tuples of
control parameters in great detail: Using tuples, the two calls to select_shape in our example program could
be combined into only one call. We will further explain the use of HALCON vectors in section 13.3 on page 95.
Chapter 14 on page 103 is dedicated to the return values of HALCON operators. Chapter 15 on page 105 gives an
C
overview over all the include files and C libraries necessary for compiling C programs and shows how to create a
stand-alone application. Finally, chapter 16 on page 109 contains example solutions for some common problems
in image processing (like edge detection).
Figure 12.1 depicts the example C program together with the input image and the results. The goal is to find the
eyes of the monkey by segmentation. The segmentation result is shown in figure 12.1 on the upper right side.
The program is quite self-explanatory. We will describe the basic principles nevertheless: First, all image pixels
with gray values greater than 128 are selected. Then all connected components of the region formed by these
pixels are calculated. The corresponding HALCON operator calculates a region tuple, and thus splits the image in
different regions (objects). From these, the mandrill’s eyes are selected by their area and shape.
This example shows how easy it is to integrate HALCON operators in any C program. Their use is very intuitive:
Users don’t have to think about the basic data structures and algorithms involved. And since all HALCON operators
are hardware independent, users don’t even have to care about things like different I/O devices. HALCON has its
own memory management and provides a sophisticated runtime environment.
88 Introducing HALCON/C
#include "HalconC.h"
int main()
{
Hobject Monkey,Thresh,Conn,Area,Eyes;
Htuple ImagePtr,ImageType;
Htuple Row,Col,Width,Height,Father,Mode,Machine,WindowHandle;
Figure 12.1: Example program with input image (upper left) and segmentation results (upper right).
The HALCON Parameter Classes 89
Chapter 13
C
exception to this rule are output control parameters of type char*. Here, the caller has to provide the memory and
only a pointer to that memory is passed to the operator.
Most HALCON operators can also be called using tuples of parameters instead of single values (so-called tuple
mode). Take the operator threshold from our example program in the previous chapter, which segments an
image and returns the segmented region: If you pass a tuple of images, it will return a tuple of regions, one for
each input image. However, in contrast to HDevelop and other programming interfaces, in HALCON/C the tuple
mode must be selected explicitly by prefixing the operator with T_ and by using tuples for all control values (see
section 13.2 on page 90 for more details). Whether an operator can be called in tuple mode can be seen in the
HALCON reference manual.
HALCON/C provides the data structure Htuple for tuples of control parameters (see section 13.2.4 on page 92
for details) and the data structure Hobject for image objects (single objects as well as object tuples — see sec-
tion 13.1).
By using image objects, HALCON provides an abstract data model that covers a lot more than simple image arrays.
Basically, there are two different types of image objects:
• Images
• Regions
A region consists of a set of coordinate values in the image plane. Regions do not need to be connected and may
include “holes.” They may even be larger than the image format. Internally, regions are stored in the so-called
runlength encoding.
Images consist of at least one image array and a region, the so-called domain. The domain denotes the pixels
that are “defined” (i.e., HALCON operators working on gray values will only access pixels in this region). But
HALCON supports multi-channel images, too: Images may consist of an (almost) arbitrary number of channels.
An image coordinate therefore isn’t necessarily represented by a single gray value, but by a vector of up to n gray
values (if the coordinate lies within the image region). This may be visualized as a “stack” of image arrays instead
of a single array. RGB- or voxel-images may be represented this way.
90 The HALCON Parameter Classes
HALCON provides operators for region transformations (among them a large number of morphological operators)
as well as operators for gray value transformations. Segmentation operators are the transition from images (gray
values) to regions.
HALCON/C provides the data type Hobject for image objects (both images and regions). In fact, Hobject is a
surrogate of the HALCON database containing all image objects. Input image objects are passed to the HALCON
operators by value as usual, output image objects are passed by reference, using the &-operator. Variables of type
Hobject may be a single image object as well as tuples of image objects. Single objects are treated as tuples with
length one.
Of course, users can access specific objects in an object tuple, too. To do so, it is necessary to extract the specific
object key (converted to integer) first, using the operators obj_to_integer or copy_obj. The number of objects
in a tuple can be queried with count_obj. To convert the keys (returned from obj_to_integer) back to image
objects again, the operator integer_to_obj has to be used. It may be noted that integer_to_obj duplicates the
image objects (Don’t worry, this doesn’t mean necessarily that the corresponding gray value arrays are duplicated
too. As long as there is only read-access, a duplication of the references is sufficient). Therefore, all extracted
objects have to be deleted explicitly from the HALCON database, using clear_obj. Figure 13.1 contains an
excerpt from a C program to clarify that approach.
...
Hobject objects; /* tuple of image objects */
Hobject obj; /* single image object */
Hlong surrogate; /* object key, converted to integer */
Htuple Tsurrogates; /* tuple of object keys */
Htuple Index,Num; /* temporary tuple for parameter passing */
Hlong i; /* loop variable */
Hlong num; /* number of objects */
...
count_obj(objects, &num);
/* variant 1: object key -> control parameter */
create_tuple_i(&Index,1);
create_tuple_i(&Num,num);
T_obj_to_integer(objects,Index,Num,&Tsurrogates);
for (i=0; i<num; i++)
{
surrogate = get_i(Tsurrogates,i);
/* process single object */
}
/* variant 2: copying objects individually */
for (i=1; i<=num; i++)
{
copy_obj(objects,&obj,i,1);
/* process single object */
}
...
Figure 13.1: Accessing the i-th image object in a tuple of image objects.
Some HALCON operators like difference allow the use of the following specific image objects as input param-
eters:
• integers,
• floating point numbers,
• character arrays (strings),
• handles
Regardless of the encoding of the HALCON library (set_system(’filename_encoding’, ...)) the HAL-
CON/C interface expects raw char pointer strings that are passed to HALCON operators and to Htuple in-
stances to be UTF-8 encoded. The encoding of the HALCON/C interface (interface encoding) can be changed
to local-8-bit encoding via a call of SetHcInterfaceStringEncodingIsUtf8(false). Note that the en-
coding must not be changed when using HDevEngine. The current interface encoding can be requested via !
IsHcInterfaceStringEncodingUtf8(). It is not recommended to switch the interface encoding back and
forth. The setting should be adjusted only once at the very beginning of the program (before the first HALCON
operator or assignment), because the Htuple structure can not store in which encoding the contained strings are
present, i.e, for all write and read accesses, the same encoding must be set. Furthermore, the interface encoding is
set globally and is therefore not suitable for multithreading programs: Changing the setting in one thread has an
effect on other threads. Note also, that UTF-8 encoded strings may take more memory space than strings in local-
8-bit-encoding. This must be considered when providing the buffer for strings returned by HALCON operators.
As long as the maximum length of the strings returned is not known for sure, it is recommended to prefer operator
calls in tuple mode over simple mode.
If the string encoding needs to be converted without changing the interface encoding, the following functions for
C
converting wchar_t* strings and char* strings to or from tuples are provided:
When converted to a different encoding, a string may need a buffer of bigger size. To check on whether you have
to allocate more memory for your string you can use the get_s_to_*-functions mentioned in the table above (see
also figure 13.7). The functions transcode a string to the respective encoding and write it into the buffer provided
by the user. If the returned size of the string is greater or equal to the provided buffer, the passed buffer size was
too small.
Using control parameter tuples in C isn’t as elegant as using image object tuples. To circumvent the missing
generic lists in C, it was necessary to introduce two different working modes into HALCON/C: The simple mode
and the tuple mode. If a tuple is necessary for at least one control parameter, the tuple mode has to be used for
operator calls. In tuple mode, all control parameters of an operator must be passed as type Htuple (Mixing of the
two modes is not possible). The tuple mode also has to be used if the number or type of values that a operator
calculates isn’t known beforehand.
Mentioning the control parameter types — How is the default type of control parameters determined for a given
operator? Basically there are three ways:
Sometimes the manuals mention more than one possible type. If only integers and floating point numbers are
allowed for a parameter, values have to be passed as parameters of type double. For all other combinations of
types, the tuple mode has to be used.
HALCON operators, that are called in tuple mode are distinguished from simple mode calls by a preceding T_.
That means,
select_shape
is a call of the HALCON operator select_shape (as described in the HALCON reference manual) in simple
mode, whereas
T_select_shape
In the so-called simple mode, all control parameters of operator calls are variables (or constants) of the data types
Hlong and double input control parameters are passed by value as usual, the corresponding output control param-
eters are passed by reference, using the &-operator. String parameters are pointers to char in both cases. Please
note, that the memory for output control parameters (in particular strings) has to be provided by the caller! We
recommend to allocate memory for at least 1024 characters for string parameters of unknown length. Output pa-
rameter values that are of no further interest can be set to NULL (e.g.,as in the call get_mbutton in figure 12.1 on
page 88).
Examples for HALCON operator calls in simple mode can be found in the C programs in figure 13.1 and figure 12.1
on page 88.
Operators with parameters resembling handles must always be called in the tuple mode as described in the follow-
ing section. The simple mode for these operators is only available in legacy handle mode (see set_system).
We mentioned already that control parameter tuples for HALCON operators need special treatment. In this chapter
we will give the details on how to construct and use those tuples. The HALCON reference manual describes a large
number of operators that don’t operate on single control values but on tuples of values. Using those operators, it is
easy to write very compact and efficient programs, because often it is possible to combine multiple similar operator
calls into a single call.
Unfortunately, C provides no generic tuple or list constructor. In contrast, HALCON allows tuples with mixed
types as control parameter values (e.g., integers mixed with floating point numbers).
Therefore, in addition to the very intuitive simple mode there is another mode in HALCON/C: the tuple mode.
Using this mode is a little more elaborate. If at least one of the control parameters of a HALCON operator is
passed as a tuple, the tuple mode has to be used for all control parameters (Mixing of both modes isn’t possible).
Furthermore, the tuple mode also has to be used if the number or type of the calculated values aren’t known
beforehand.
Syntactically, tuple mode is distinguished from simple mode by a T_ preceding the operator name. For example,
calling disp_circle in tuple mode is done by
13.2 Control parameters 93
T_disp_circle(...).
To ease the usage of the tuple mode, HALCON/C provides the abstract data type Htuple for control parameter
tuples. Objects of type Htuple may be constructed using arrays of the types
• Hlong* for integer arrays (HALCON type LONG_PAR),
• double* for floating point arrays (DOUBLE_PAR),
• char** for string arrays (strings, STRING_PAR) or
• Hphandle* for handle arrays (HANDLE_PAR)
Additionally, a MIXED_PAR array type is supported that can hold an array with any of the three native value types
in arbitrary combination. The usage of these four array types is transparent.
Control parameter tuples must be created, deleted, and manipulated using the appropriate HALCON/C procedures
only (overview in figures 13.2, 13.3, 13.4 and 13.5).
The rules for parameter passing are valid in tuple mode, too: Input control parameters (type Htuple) are passed
by value as usual, output control parameters are passed by reference, using the &-operator. For output parameters
that are of no further interest you can pass NULL.
The following sections describe the five most important steps when calling a HALCON operator in tuple mode:
• allocate memory (section 13.2.4.1 on page 93)
• construct input parameters (section 13.2.4.2 on page 93)
• call operator (section 13.2.4.3 on page 93)
C
• process output parameters (section 13.2.4.4 on page 93)
• free memory (section 13.2.4.5 on page 94)
Section 13.2.4.6 on page 94 contains an example.
Finally, section 13.2.4.7 on page 94 describes a generic calling mechanism that can be used in interpreters or
graphical user interfaces.
First, memory must be allocated for all tuples of input control parameters, using create_tuple or
create_tuple_type, respectively (see figures 13.2). Memory for output control parameter tuples is allocated
by HALCON/C (a call of create_tuple isn’t necessary). With create_tuple_i etc. you can create a tuple of
length 1 and set its value in a single step (see figures 13.3). With reuse_tuple_i etc. you can reuse an existing
tuple, i.e., destroy and reallocate it and set a single value (see figures 13.4).
You set tuple elements using the appropriate procedures set_*. set_s, which insert a string into a tuple, allocates
the needed memory by itself, and then copies the string (see figure 13.5).
Then, the HALCON operator is actually called. The operator name is (as already explained) preceded by a T_ to
denote tuple mode.
Further processing of the output parameter tuples takes place, using the procedures length_tuple, get_type
(see figure 13.2) and get_* (see figure 13.6 and figure 13.7). When processing strings (using get_s), please note
that the allocated memory is freed automatically upon deleting the tuple with destroy_tuple. If the string has
to be processed even after the deletion of the tuple, the whole string must be copied first. Also note that output
handles might be freed when deleting the last tuple. If a handle should be used further, it should be kept in a tuple.
94 The HALCON Parameter Classes
void create_tuple_type(tuple,length,type)
Htuple *tuple;
Hlong length;
Hlong type;
/* creates a tuple of 'type' that can hold 'length' entries.
* 'type' can hold either LONG_PAR, DOUBLE_PAR, STRING_PAR,
* HANDLE_PAR, or MIXED_PAR. */
Finally the memory allocated by all the tuples (input and output) has to be freed again. This is done with
destroy_tuple. If you still need the values of the tuple variables, remember to copy them first. Now, the
whole series can start again — using different or the same tuple variables.
An example for the tuple mode can be found in figure 13.8 or the file example3.c): The aim is to obtain infor-
mation about the current HALCON system state. The operator get_system(’?’,Values) (here in HDevelop
syntax) returns all system flags with their current values. Since in our case neither number nor type of the output
parameters is known beforehand, we have to use tuple mode for the actual operator call in HALCON/C. The rest
of the program should be self explanatory.
There is also an alternative generic calling mechanism for HALCON operators in tuple mode. This mechanism
is intended for the use in interpreters or graphical user interfaces:
T_call_halcon_by_id(id, ...)
calls the HALCON operator id in tuple mode, passing input parameters and getting the output parameters (see fig-
ure 13.9 on page 101 for the complete signature). The id of an operator can be requested with get_operator_id.
13.3 Vectors 95
void create_tuple_i(tuple,value)
Htuple *tuple;
Hlong val;
/* creates a tuple with specified integer value */
void create_tuple_d(tuple,value)
Htuple *tuple;
double val;
/* creates a tuple with specified double value */
void create_tuple_h(tuple,value)
Htuple *tuple;
Hphandle val;
/* creates a tuple with specified handle value */
void create_tuple_s(tuple,value)
Htuple *tuple;
char *val;
/* creates a tuple with specified string value */
void create_tuple_s_from_local8bit(tuple,value)
Htuple *tuple;
char *val;
/* creates a tuple with specified string value converted */
/* from local-8-bit encoding */
void create_tuple_s_from_utf8(tuple,value)
C
Htuple *tuple;
char *val;
/* creates a tuple with specified string value converted */
/* from UTF-8 encoding */
void create_tuple_s_from_wcs(tuple,value)
Htuple *tuple;
wchar_t *val;
/* creates a tuple with specified string value converted */
/* from wide-character encoding */
13.3 Vectors
HALCON/C provides the data structure Hvector for the use of the vector functionality of the HDevelop language.
A HALCON vector is a container that can hold an arbitrary number of elements of the identical data type (i.e.,
tuples, iconic objects, or vectors) and dimension. The type of a vector, i.e., its dimension and the type of its
elements is defined when initializing the vector instance and cannot be changed during its lifetime. A vector with
one dimension may be a vector of tuples or a vector of iconic objects. A two-dimensional vector may be a vector
of vectors of tuples or a vector of vectors of iconic objects, and so on.
Construction of Vectors
When creating such a vector in HALCON/C you have to differ between vectors of iconic objects and vectors of
tuples.
96 The HALCON Parameter Classes
void reuse_tuple_i(tuple,val)
Htuple *tuple;
Hlong val;
/* reuses a tuple with specified integer value */
void reuse_tuple_d(tuple,val)
Htuple *tuple;
double val;
/* reuses a tuple with specified double value */
void reuse_tuple_h(tuple,val)
Htuple *tuple;
Hphandle val;
/* reuses a tuple with specified handle value */
void reuse_tuple_s(tuple,val)
Htuple *tuple;
char *val;
/* reuses a tuple with specified string value */
void reuse_tuple_s_from_local8bit(tuple,val)
Htuple *tuple;
char *val;
/* reuses a tuple with specified string value converted */
/* from local-8-bit encoding */
void reuse_tuple_s_from_utf8(tuple,val)
Htuple *tuple;
char *val;
/* reuses a tuple with specified string value converted */
/* from UTF-8 encoding */
void reuse_tuple_s_from_wcs(tuple,val)
Htuple *tuple;
wchar_t *val;
/* reuses a tuple with specified string value converted */
/* from wide-character encoding */
These calls create empty vectors of one dimension, e.g., a vector of tuples. It is also possible to create multi-
dimensional vectors, i.e., a vector of vectors of tuples or a vector of vectors of iconic objects and so on, by
specifying the number of dimensions in the call.
V_create_object_vector(2,&vectorObjMulti);
Note that the vector type and its dimension cannot be changed after the creation of the vector.
C
/* memory necessary for the string is allocated by set_s */
V_get_vector_tuple(vectorTup,index,tuple);
For accessing elements in vectors of iconic objects V_get_vector_obj can be used instead.
V_get_vector_obj(image,vectorTup,index);
98 The HALCON Parameter Classes
The element to be accessed is specified by its index in form of a tuple. It may either contain a single index of an
element in one-dimensional vectors or several indices of the corresponding subvector(s) and its subelement(s) in
multi-dimensional vectors.
You may also query a whole subvector of a multi-dimensional vector using V_get_vector_elem.
Before accessing the contents of a vector you may set some vector elements first. Again a distinction is made
between vectors of tuples, vectors of iconic objects, and multi-dimensional vectors. The following lines show how
to set vector elements of one-dimensional vectors.
The element to be set is again addressed by the specified index, which is represented as a Htuple. Beside the
index, the vector itself and the respective Hobject or Htuple to be set (e.g., image or tuple) must be added to
the call.
For multi-dimensional vectors the specified index tuple must contain the indices of the subvector(s) and its subele-
ment. The following code lines show the whole process from creating a two-dimensional vector, the image to be
set, and the index tuple up to specifying the indices and finally setting the element of the vector.
13.3 Vectors 99
C
Hlong *get_s_to_wcs(buffer,size,tuple,index) or macro GS_W(tuple,index)
wchar_t* buffer;
Hlong size;
Htuple tuple;
Hlong index;
/* Copies the (wide-character) string at position */
/* 'index' into 'buffer'. 'size' determines the size of the */
/* buffer. The return value determines the size of the */
/* string, that would be written. If the returned length of */
/* the string is greater or equal to the provided */
/* buffer, the buffer was too small. */
/* Attention: indices must be in [0,length_tuple(tuple) - 1] */
V_create_object_vector(2,&vectorObjMulti);
read_image(&img,"Image");
set_i(indices,0,0);
set_i(indices,1,1);
#include <stdio.h>
main ()
{
Htuple In,SysFlags,Info;
Hlong i,num;
printf("System information:\n");
/* prepare query */
create_tuple(&In,1);
/* "?" = list of all informations */
set_s(In,"?",0);
T_get_system(In,&SysFlags);
destroy_tuple(In);
num = length_tuple(SysFlags);
for (i=0; i<num; i++)
{
create_tuple(&In,1);
set_s(In,get_s(SysFlags,i),0);
printf("%s ",get_s(SysFlags,i));
T_get_system(In,&Info);
destroy_tuple(In);
if (length_tuple(Info) > 0)
{
switch(get_type(Info,0)) {
case INT_PAR:
printf("(Hlong): %" LONG_FORMAT "d\n",get_i(Info,0));
break;
case DOUBLE_PAR:
printf("(double): %f\n",get_d(Info,0));
break;
case STRING_PAR:
printf("(string): %s\n",get_s(Info,0));
break;
case HANDLE_PAR:
printf("(handle): %" LONG_FORMAT "d\n",(Hlong)get_h(Info,0));
break;
}
}
else
{
printf("(--): no data\n");
}
destroy_tuple(Info);
}
}
Figure 13.8: Tuple mode example program: Printing the current HALCON system state.
Destruction of Vectors
If a Hvector is not needed for further processing its contents and allocated memory must be freed with
V_destroy_vector.
V_destroy_vector(vectorTup);
Additional Information
In addition to the previously mentioned basic information the data structure of Hvector provides some more func-
tionalty, e.g., inserting or removing vector elements, or concatenation of vectors. Please refer to the corresponding
header file Hvector.h in %HALCONROOT%\include\halconc for further information.
13.3 Vectors 101
C
* - the tuple arrays are passed directly to the call -> this method is
* thread-safe
*-----------------------------------------------------------------------*/
int get_operator_id(const char* name);
Figure 13.9: Generic calling mechanism for the HALCON/C tuple mode.
102 The HALCON Parameter Classes
Return Values of HALCON Operators 103
Chapter 14
HALCON operator return values (type Herror) can be divided into two categories:
• Messages (H_MSG_*) and
• Errors (H_ERR_*).
HALCON operators return H_MSG_TRUE, if no error occurs. Otherwise, a corresponding error value is returned.
Errors in HALCON operators usually result in an exception, i.e., a program abort with the appropriate error mes-
sage in HALCON/C (default exception handling). However, users can disable this mechanism (with a few excep-
tions, like errors in Htuple operators), using
C
set_check("~give_error");
to provide their own error handling routines. In that case, the operator get_error_text is very useful: This
operator returns the plain text message for any given error code. Finally, the operator
set_check("give_error");
enables the HALCON error handling again. Several examples showing the handling of error messages can be seen
in the file example5.c.
104 Return Values of HALCON Operators
Generation of HALCON/C Applications 105
Chapter 15
The HALCON distribution contains examples for creating an application with HALCON/C++. The following
sections show
• the relevant directories and files (section 15.1 on page 105)
• the list of provided example applications (section 15.2 on page 106)
• the relevant environment variables (section 15.3 on page 106)
• how to create an executable under Windows (section 15.4 on page 107)
C
• how to create an executable under Linux (section 15.5 on page 107)
The HALCON distribution contains examples for building an application with HALCON/C. Here is an overview
of HALCON/C (Windows notation of paths):
include\HalconC.h:
include file; contains all user-relevant definitions of the HALCON system and the declarations necessary for
the C interface.
bin\%HALCONARCH%\halcon.dll,
lib\%HALCONARCH%\halcon.lib:
The HALCON library (Windows).
bin\%HALCONARCH%\halconc.dll,
lib\%HALCONARCH%\halconc.lib:
The HALCON/C library (Windows).
bin\%HALCONARCH%\halconxl.dll, halconcxl.dll,
lib\%HALCONARCH%\halconxl.lib, halconcxl.lib:
The corresponding libraries of HALCON XL (Windows).
lib/$HALCONARCH/libhalcon.so:
The HALCON library (Linux).
lib/$HALCONARCH/libhalconc.so:
The HALCON/C library (Linux).
lib/$HALCONARCH/libhalconxl.so,libhalconcxl.so:
The corresponding libraries of HALCON XL (Linux).
include\HProto.h:
External function declarations.
106 Generation of HALCON/C Applications
There are several example programs in the HALCON/C distribution (%HALCONEXAMPLES% \c\source\). To
experiment with these examples we recommend to create a private copy in your working directory.
A special case is the example program example_multithreaded1.c. It demonstrates the use of HALCON in
a multithreaded application. Please note, that it does not make sense to run the example on a single-processor or
single-core computer.
In the following, we briefly describe the relevant environment variables; see the Installation Guide, section A.2 on
page 45, for more information, especially about how to set these variables. Note, that under Windows, all necessary
variables are automatically set during the installation.
15.4 Windows 107
While a HALCON program is running, it accesses several files internally. To tell HALCON where to look for these
files, the environment variable HALCONROOT has to be set. HALCONROOT points to the HALCON home directory; it
is also used in the sample makefile.
The variable HALCONARCH describes the platform HALCON is used on. Please refer to the Installation Guide,
section 1.4 on page 8, for more information.
The variable %HALCONEXAMPLES% indicates where the provided examples are installed.
If user-defined packages are used, the environment variable HALCONEXTENSIONS has to be set. HALCON will
look for possible extensions and their corresponding help files in the directories given in HALCONEXTENSIONS.
Two things are important in connection with the example programs: The default directory for the HALCON
operator read_image to look for images is %HALCONROOT%\images. If the images reside in different directo-
ries, the appropriate path must be set in read_image or the default image directory must be changed, using
set_system("image_dir","..."). This is also possible with the environment variable HALCONIMAGES. It has
to be set before starting the program.
The second remark concerns the output terminal under Linux. In the example programs, no host name is
passed to open_window. Therefore, the window is opened on the machine that is specified in the envi-
ronment variable DISPLAY. If output on a different terminal is desired, this can be done either directly in
open_window(...,"hostname",...) or by specifying a host name in DISPLAY.
In order to link and run applications under Linux, you have to include the HALCON library path
$HALCONROOT/lib/$HALCONARCH in the system variable LD_LIBRARY_PATH.
C
Your own C programs that use HALCON operators must include the file HalconC.h, which contains all user-
relevant definitions of the HALCON system and the declarations necessary for the C interface. Do this by adding
the command
#include "HalconC.h"
near the top of your C file. In order to create an application you must link the library halconc.lib/.dll to your
program.
The example projects show the necessary Visual C++ settings. For the examples the project should be of the WIN
32 ConsoleApplication type. Please note that the Visual C++ compiler implicitly calls “Update all dependencies”
if a new file is added to a project. Since HALCON runs under Linux as well as under Windows, the include
file HalconC.h includes several Linux-specific headers as well if included under Linux. Since they don’t exist
under Windows, and the Visual C++ compiler is dumb enough to ignore the operating-system-specific cases in the
include files, you will get a number of warning messages about missing header files. These can safely be ignored.
Please assure that the stacksize is sufficient. Some sophisticated image processing problems require up to 1 MB
stacksize, so make sure to set the settings of your compiler accordingly (See your compiler manual for additional
information on this topic).
HALCON XL applications: If you want to use HALCON XL, you have to link the libraries halconxl.lib/.dll
and halconcxl.lib/.dll instead of halcon.lib/.dll and halconc.lib/.dll in your project.
Your own C programs that use HALCON operators must include the file HalconC.h, which contains all user-
relevant definitions of the HALCON system and the declarations necessary for the C interface. Do this by adding
the command
#include "HalconC.h"
108 Generation of HALCON/C Applications
near the top of your C file. Using this syntax, the compiler looks for HalconC.h in the current directory only.
Alternatively you can tell the compiler where to find the file, giving it the -I<pathname> command line flag to
denote the include file directory.
To create an application, you have to link two libraries to your program: The library libhalconc.so contains the
various components of the HALCON/C interface. libhalcon.so is the HALCON library.
HALCON XL applications: If you want to use HALCON XL, you have to link the libraries libhalconcxl.so
and libhalconxl.so instead.
Please take a look at the example makefiles for suitable settings. If you call gmake without further arguments, the
example application example1 will be created. To create the other example applications (e.g., example2), call
make example2
You can use the example makefiles not only to compile and link the example programs but also your own programs
(called e.g. test.c) by calling
make test
You can link the program to the HALCON XL libraries by adding XL=1 to the make command, for example
Chapter 16
This final chapter shows the possibilities of HALCON and HALCON/C on the basis of several simple image
processing problems.
16.1 Thresholding
C
read_image(&Image,"File_xyz");
threshold(Image,&Thres,0.0,120.0);
connection(Thres,&Conn);
select_shape(Conn,&Result,"area","and",10.0,100000.0);
read_image(&Image,"File_xyz");
sobel_amp(Image,&Sobel,"sum_abs",3);
threshold(Sobel,&Max,30.0,255.0);
skeleton(Max,&Edges);
read_image(&Image,"File_xyz");
mean_image(Image,&Lp,11,11);
dyn_threshold(Image,Lp,&Thres,5.0,"light");
• The size of the filter mask (11 x 11, in this case) depends directly on the size of the expected objects (both
sizes are directly proportional to each other).
• In this example, the dynamic threshold operator selects all pixels that are at least 5 gray values brighter than
their surrounding (11 x 11) pixels.
read_image(&Image,"File_xyz");
Filter = "ee";
texture_laws(Image,&TT,Filter,2,5);
mean_image(TT,&Lp,31,31);
threshold(Lp,&Seg,30.0,255.0);
• The size of the circular mask (3.5, in this case) determines the smallest size of the remaining objects.
• It is possible to use any kind of mask for object elimination (not only circular masks).
• segmentation(...) is used to denote a segmentation operator that calculates a tuple of image objects
(Seg).
• The rectangle’s shape and size (length and width) determine the smallest size of the remaining objects.
• The rectangle’s orientation determines the orientation of the remaining regions (In this case, the main axis
and the horizontal axis form an angle of 0.5 rad).
• Lines with an orientation different from the mask’s (i.e., the rectangle’s) orientation are suppressed.
• segmentation(...) is used to denote a segmentation operator that calculates a tuple of image objects
(Seg).
The third (and final) application example of morphological operations covers another common image processing
problem — the smoothing of region boundaries and closing of small holes in the regions:
...
segmentation(Image,&Seg);
gen_circle(&Mask,100.0,100.0,3.5);
closing(Seg,Mask,&Res);
• For the smoothing of region boundaries, circular masks are suited best.
• The mask size determines the degree of the smoothing.
• segmentation(...) is used to denote a segmentation operator that calculates a tuple of image objects
(Seg).
C
112 Typical Image Processing Problems
Part V
Using HDevEngine
Introducing HDevEngine 115
Chapter 17
Introducing HDevEngine
As the name suggests, HDevEngine is the “engine” of HDevelop. This chapter briefly introduces you to its basic
concepts. Chapter 18 on page 119 explains how to use it in C++ applications, and chapter 19 on page 131 how to
use it in .NET applications (C#, Visual Basic .NET, etc.). Additional information that is independent of the used
programming language can be found in chapter 20 on page 153.
HDevEngine
machine vision part of an application by replacing individual HDevelop files.
What is HDevEngine?
HDevEngine is provided as a C++ class library and a .NET assembly. It consists of the following classes:
• HDevEngine (C++), HDevEngine (.NET)
This is the main class of HDevEngine. With it you manage global settings.
• HDevProgram (C++), HDevProgram (.NET)
With this class you load an HDevelop program and get general information about it.
• HDevProgramCall (C++), HDevProgramCall (.NET)
With this class you execute a program and get the values of its variables.
• HDevProcedure (C++), HDevProcedure (.NET)
With this class you load an HDevelop procedure and get general information about it.
• HDevProcedureCall (C++), HDevProcedureCall (.NET)
With this class you pass input parameters to an HDevelop procedure, execute it, and retrieve its output
parameters.
116 Introducing HDevEngine
• HDevOperatorImplCpp (C++),
IHDevOperators, HDevOpMultiWindowImpl, HDevOpFixedWindowImpl (.NET)
As noted above, HDevEngine does not implement internal HDevelop operators like dev_display. All
HDevEngine variants provide a class or interface to create your own implementation for those operators
that are useful in your application. HDevEngine/.NET also includes two convenience classes that provide a
default implementation of the operators.
• HDevEngineException (C++), HDevEngineException (.NET)
Instances of this class are “thrown” if an exception occurs inside HDevEngine, e.g., because the application
tried to load a non-existing program or because of an error inside an operator in the executed program or
procedure.
• When developing the image processing part of your application, you will of course create an HDevelop
program. Thus, as a first test of your (programmed) application it is useful to execute the HDevelop pro-
gram via HDevEngine. This test will already assure that the general configuration of your application
(environment variables, procedure path, etc.) is correct.
The HDevelop program itself should of course use the same procedures that you plan to execute from the
programmed application.
• After you finished its development, you integrate the image processing part into your programmed ap-
plication by executing the corresponding HDevelop procedures. Typically, you display image process-
ing results by using the methods of the underlying HALCON programming language interface, i.e., HAL-
CON/C++ for HDevEngine/C++, or HALCON/.NET for HDevEngine/.NET (C#, Visual Basic .NET, etc.),
but you can also encapsulate recurring display tasks in HDevelop procedures.
• Whether to use local or external procedures depends on the reusability of the procedure. External proce-
dures should be used for widely reusable tasks, e.g., opening the connection to and configuring the image
acquisition device, or for standard image processing tasks like bar code or data code reading. Groups of
closely related external procedures may be combined into a procedure library to keep them as a unit in a
single file.
In contrast, local procedures are suitable for not completely reusable tasks, e.g., for training and con-
figuring a shape model to find objects. Then, different applications can use their optimized variant of the
procedure instead of creating a single procedure with many parameters and internal switches that suits all
applications.
Of course, using local procedures means that you must load the HDevelop program that contains them.
However, as noted above, loading and executing the corresponding HDevelop program is a good test of the
general configuration of the application.
the used procedures of a HDevelop program. See section 18.3 on page 129 (C++) and section 19.3 on page 152
(.NET) for more information about using the JIT compiler.
JIT compilation is not supported for procedures that use any of the following features:
• dev_error_var
• procedure calls using the par_start qualifier
• par_join
• dev_display with a vector expression as variable
• for loop with a vector expression as index variable
• call of any procedure that cannot be JIT compiled due to the above reasons.
If one of these features is found, the corresponding procedure is executed uncompiled as before by HDevEngine.
HDevEngine XL
Like HALCON, the language-dependent versions of HDevEngine are provided in two variants: based on HALCON
and based on HALCON XL. The latter use the XL versions of the HALCON library and of HALCON/C++, and
HALCON/.NET, respectively.
HDevEngine
118 Introducing HDevEngine
HDevEngine in C++ Applications 119
Chapter 18
This chapter explains how to use HDevEngine in C++ applications. Section 18.1 on page 119 quickly summarizes
some basic information, e.g., how to compile and link such applications. Section 18.2 on page 120 then explains
how to use HDevEngine based on examples.
An overview about the classes of HDevEngine and their methods can be found in section 20.1 on page 153.
HDevEngine
• In your application, you include the main header file HalconCpp.h and HDevEngine’s header file
HDevengineCpp.h and use the corresponding namespaces on Windows and Linux systems:
# include "HalconCpp.h"
# include "HDevEngineCpp.h"
• To compile the application, use the following include paths on Windows systems
/I "$(HALCONROOT)\include" /I "$(HALCONROOT)\include\halconcpp"
/I "$(HALCONROOT)\include\hdevengine"
HDevEngine XL applications: If you want to use HDevEngine XL, link the following libraries on Windows
systems
This section explains how to employ HDevEngine based on example applications, which reside in the subdirectory
%HALCONEXAMPLES%\hdevengine\cpp. Like the examples for HALCON/C++ described in chapter 7 on page
47, they are provided as Visual Studio projects for Windows systems and with makefiles for Linux, macOS, and
Windows systems.
The example applications show how to
• execute an HDevelop program (section 18.2.1 on page 120)
• execute HDevelop procedures (section 18.2.2 on page 122)
• implement display operators (section 18.2.3 on page 125)
• error handling (section 18.2.4 on page 126)
Section 18.2.5 on page 128 contains additional information for creating multithreaded applications using HDev-
Engine.
In this section, we explain how to load and execute an HDevelop program with HDevEngine. The code fragments
stem from the example application exec_program (source file exec_program.cpp), which checks the boundary
of a plastic part for fins. Figure 18.1 on page 121 shows a screenshot of the application.
First, we include the main header files of HALCON/C++ and of HDevEngine and the corresponding names-
paces. Note that in this example application the HDevEngine header file is already included via the header file
my_hdevoperatorimpl.h so we don’t have to include the HDevEngineCpp.h header file explicitly:
# include "HalconCpp.h"
# include "my_hdevoperatorimpl.h"
The main procedure just calls a procedure that does all the work of the example. First, we create an instance of the
main HDevEngine class HDevEngine.
HDevEngine my_engine;
The path to the HDevelop program and the external procedure path are stored in string variables, with a suitable
syntax for the used platform. Note that in Windows applications you can use both / and \ in path strings:
std::string halcon_examples =
(std::string)HSystem::GetSystem("example_dir")[0].S();
std::string program_path(halcon_examples), ext_proc_path(halcon_examples);
program_path += "/hdevengine/hdevelop/fin_detection.hdev";
ext_proc_path += "/hdevengine/procedures";
If the HDevelop program calls external procedures, you must set the external procedure path with the method
HDevEngine
SetProcedurePath:
my_engine.SetProcedurePath(ext_proc_path.c_str());
Now, we create an instance of the class HDevProgram and load the HDevelop program with the method
LoadProgram. Note that LoadProgram changes the working directory if a program is loaded successfully.
The call is encapsulated in a try...catch-block to handle exceptions occurring in the HDevEngine method,
e.g., because the file name was not specified correctly. A detailed description of error handling can be found in
section 18.2.4 on page 126.
HDevProgram my_program;
try
{
my_program.LoadProgram(program_path.c_str());
}
catch (HDevEngineException& hdev_exception)
...
If the program could be loaded successfully, we execute the program with the method Execute and store the
returned instance of the class HDevProgramCall in a variable for later use:
Figure 18.2: Executing an external HDevelop procedure that detects fins on a boundary.
That’s all you need to do to execute an HDevelop program. You can also access its “results”, i.e., its variables
with the method GetCtrlVarTuple. In the example program, the area of the extracted fin is queried and then
displayed:
Note that program variables can only be accessed when the program has terminated.
How to display results while the program is running is described in section 18.2.3 on page 125.
In this section, we explain how to load and execute an external HDevelop procedure with HDevEngine. The code
fragments in the following stem from the example application exec_extproc (source file exec_extproc.cpp),
which, like the example described in the previous section, checks the boundary of a plastic part for fins. Figure 18.2
on page 122 shows a screenshot of the application.
In contrast to the previous example, the result display is programmed explicitly in HALCON/C++ instead of relying
on the internal display operators. How to provide your own implementation of the internal display operators is
described in section 18.2.3 on page 125.
As when executing an HDevelop program, we include the main header files of HALCON/C++ and of HDevEn-
gine and the namespaces. In this example application the HDevEngine header file is included via the header file
my_error_output.h so we don’t need to include it explicitly. The main procedure just calls the procedure run
that does all the work of the example. We create an instance of the main HDevEngine class HDevEngine and
directly set the external procedure path with the method SetProcedurePath. If the external procedure is from
a procedure library, the external procedure path may include the name of the library file.
18.2 How to Use HDevEngine/C++ 123
# include "HalconCpp.h"
# include "my_error_output.h"
void run(void)
{
std::string halcon_examples =
(std::string)HSystem::GetSystem("example_dir")[0].S();
std::string ext_proc_path(halcon_examples);
...
HDevEngine().SetProcedurePath(ext_proc_path.c_str());
DetectFin();
}
In the “action” routine, we load the external procedure with the constructor of the class HDevProcedure,
specifying the name of the procedure, and store the returned procedure call in an instance of the
class HDevProcedureCall. The call is encapsulated in a try...catch-block to handle excep-
tions occurring in the constructor, e.g., because the file name or the procedure path was not speci-
fied correctly. A detailed description of error handling can be found in section 18.2.4 on page 126.
void DetectFin()
{
try
{
HDevProcedure proc("detect_fin");
HDevProcedureCall proc_call(proc);
HDevEngine
Before executing the procedure, we open and initialize the graphics window in which the results are to be
displayed and load an example image sequence:
HWindow win(00,100,384,288);
win.SetPart(0,0,575,767);
win.SetDraw("margin");
win.SetLineWidth(4);
HFramegrabber fg("File",1,1,0,0,0,0,"default",-1,"default",-1,"default",
image_sequ_str,"default",-1,-1);
Each image should now be processed by the procedure, which has the following signature, i.e., it expects an image
as (iconic) input parameter and returns the detected fin region and its area as iconic and control output parameter,
respectively:
We pass the image as input object by storing it in the instance of HDevProcedureCall with the method
SetInputIconicParamObject. Which parameter to set is specified via its index (starting with 1); there is also a
method to specify it via its name (see section 20.1.5 on page 164):
124 HDevEngine in C++ Applications
proc_call.SetInputIconicParamObject(1,image);
As as alternative to passing parameters, you can also use global variables in HDevEngine (compare
the HDevelop User’s Guide, section 8.3.2 on page 275). You set the value of a global variable with
the methods SetGlobalIconicVarObject or SetGlobalCtrlVarTuple and query it with the methods
GetGlobalIconicVarObject and GetGlobalCtrlVarTuple.
proc_call.Execute();
If the procedure was executed successfully, we can access its results, i.e., the fin region and its area, with the
methods GetOutputIconicParamObject and GetOutputCtrlParamTuple of the class HDevProcedureCall;
again, you can specify the parameter via its index or name (see section 20.1.5 on page 164).
Now, we display the results in the graphics window. Note how we access the area by selecting the first element
of the returned tuple:
char fin_area_str[200];
sprintf(fin_area_str,"Fin Area: %ld",(long)(fin_area[0].L()));
win.DispImage(image);
win.SetColor("red");
win.DispRegion(fin_region);
win.SetColor("white");
win.SetTposition(150,20);
win.WriteString(fin_area_str);
The example application exec_procedures (source file exec_procedures.cpp) executes local and external
HDevelop procedures with HDevEngine. It mimics the behavior of the HDevelop program described in sec-
tion 18.2.1 on page 120. The display of results is partly programmed explicitly and partly delegated to an HDe-
velop procedure, using the implementation of the internal display operators described in section 18.2.3 on page
125.
Local and external procedures are created and executed in exactly the same way. The only difference is that in order
to use a local procedure, you must load the program it is contained in, whereas to load external procedures you must
set the procedure path. HDevProcedure provides different constructors to facilitate this task (see section 20.1.4
on page 161).
18.2 How to Use HDevEngine/C++ 125
18.2.3 Display
In this section, we explain how to provide your own implementation of HDevelop’s internal display operators. The
files my_hdevoperatorimpl.h and my_hdevoperatorimpl.cpp contain an example implementation, which
is used in the applications exec_program (source file exec_program.cpp), which was already discussed in
section 18.2.1 on page 120, and exec_procedures (source file exec_procedures.cpp).
In fact, HDevEngine does not provide an implementation of the internal display operators but provides the
class HDevOperatorImplCpp, which contains empty virtual methods for all those operators that you can im-
plement yourself. The methods are called like the object-oriented version of the operators, e.g., DevDisplay for
dev_display and have the same parameters (see section 20.1.6 on page 166 for the definition of the class).
The first step towards the implementation is to derive a child of this class and to specify all meth-
ods that you want to implement. The example file implements the operators dev_open_window,
dev_set_window_extents, dev_set_part, dev_set_window, dev_get_window, dev_clear_window,
dev_clear_window, dev_close_window, dev_display, dev_set_draw, dev_set_shape, dev_set_color,
dev_set_colored, dev_set_lut, dev_set_paint, and dev_set_line_width:
HDevEngine
const HalconCpp::HTuple& row2,
const HalconCpp::HTuple& col2);
virtual int DevSetWindow(const HalconCpp::HTuple& win_id);
virtual int DevGetWindow(HalconCpp::HTuple* win_id);
virtual int DevClearWindow();
virtual int DevCloseWindow();
virtual int DevDisplay(const HalconCpp::HObject& obj);
virtual int DevDispText(const HalconCpp::HTuple& string,
const HalconCpp::HTuple& coordSystem,
const HalconCpp::HTuple& row,
const HalconCpp::HTuple& column,
const HalconCpp::HTuple& color,
const HalconCpp::HTuple& GenParamName,
const HalconCpp::HTuple& GenParamValue);
virtual int DevSetDraw(const HalconCpp::HTuple& draw);
virtual int DevSetContourStyle(const HalconCpp::HTuple& style);
virtual int DevSetShape(const HalconCpp::HTuple& shape);
virtual int DevSetColor(const HalconCpp::HTuple& color);
virtual int DevSetColored(const HalconCpp::HTuple& colored);
virtual int DevSetLut(const HalconCpp::HTuple& lut);
virtual int DevSetPaint(const HalconCpp::HTuple& paint);
virtual int DevSetLineWidth(const HalconCpp::HTuple& width);
};
In addition to these methods, the class contains methods to handle multiple graphics windows. These methods use
a second class that manages all open windows. This class is thread-safe and reentrant but not described in detail in
this section.
126 HDevEngine in C++ Applications
class WinIdContainer
In the executed HDevelop program, two graphics windows are used, one for the main display and one for zooming
into the image (see figure 18.1 on page 121).
To use the implementation of HDevOperatorImplCpp, you include the header file:
#include "my_hdevoperatorimpl.h"
With the method SetHDevOperatorImpl, you pass an instance of your version of HDevOperatorImplCpp to
HDevEngine, which then calls its methods when the corresponding operator is used in the HDevelop program or
procedure.
my_engine.SetHDevOperatorImpl(&op_impl);
Now, we take a closer look at the implementation of the display operators in the example. It tries to mimic the
behavior in HDevelop: Multiple graphics windows can be open, with one being “active” or “current”. The methods
for the internal display operators simply call the corresponding non-internal display operator: For example, a call
to dev_display in the HDevelop program is “redirected” in DevDisplay to disp_obj, with the iconic object to
display and the handle of the active window as parameters:
As you can see, these operators can be implemented quite easily. The implementation of the operators for handling
graphics windows is not described here; we recommend to use the example implementation as it is because it
provides all the necessary functionality for single- and multithreaded applications.
In this section, we take a closer look at exceptions in HDevEngine. The code fragments in the following stem from
the example application error_handling (source file error_handling.cpp), which provokes different types of
exceptions and “catches” them.
HDevEngine “throws” exceptions in form of the class HDevEngineException, which contains the type (category)
of the exception, a message describing the exception, and, depending on the exception type, information like the
name of the executed procedure or the HALCON error code (see section 20.1.7 on page 166 for the declaration of
the class).
The example code for displaying information about exceptions in a graphics window is contained in the files
my_error_output.cpp and my_error_output.h. You can use it in your application by including the header
file:
#include "my_error_output.h"
18.2 How to Use HDevEngine/C++ 127
The files provide two procedures. The simpler one displays only the error message and waits for a mouse click to
continue:
void DispMessage(const char* message)
{
HWindow win(100,100,ERR_WIN_WIDTH_SIMPLE,ERR_WIN_HEIGHT_SIMPLE,
NULL,"visible","");
win.SetPart(0,0,ERR_WIN_HEIGHT_SIMPLE-1,ERR_WIN_WIDTH_SIMPLE-1);
win.SetColor("yellow");
win.SetTposition(10,10);
WriteMessageNL(win,message);
The more complex one prints all available information for the exception (only relevant code shown):
HWindow win(100,100,ERR_WIN_WIDTH_COMPLEX,ERR_WIN_HEIGHT_COMPLEX,
NULL,"visible","");
WriteMessageNL(win,exception.Message());
HDevEngine
WriteMessageNL(win,text);
This procedure is called when an exception occurs. The example provokes different errors and displays the corre-
sponding information; some of them are described in the following. Figure 18.3 on page 128 displays an exception
that occurred because the application tried to load a non-existing HDevelop program (category ExceptionFile).
try
{
program.LoadProgram(wrong_program_path.c_str());
}
catch (HDevEngineException &hdev_exception)
{
DispErrorMessage(hdev_exception,
"Error #1: Try to load a program that does not exist");
}
The same exception category occurs when a program is loaded whose external procedures are not found (see
figure 18.4 on page 128).
The exception displayed in figure 18.5 on page 128 occurs because an input iconic parameter is not initialized
(category ExceptionInpNotInit). It contains very detailed information about where the error occurred and why.
128 HDevEngine in C++ Applications
Figure 18.3: Content of the exception if an HDevelop program could not be found.
Figure 18.4: Content of the exception if external procedures of an HDevelop program could not be loaded.
The exception displayed in figure 18.6 on page 129 is provoked by calling an operator with an invalid parameter
(category ExceptionCall).
With the method UserData (see section 20.1.7 on page 166), you can also access user exception data
that is thrown within an HDevelop program or procedure by the operator throw similarly to the operator
dev_get_exception_data.
In case of an exception (which is not caught within the procedure) the procedure call is cleaned up. This means all
subthreads are destroyed and all values of input and output parameters are cleared. Therefore, we recommend to
always set all input parameters before executing a call even if some of them did not change.
Note that you can configure the behavior of HDevEngine when loading programs or procedures that contain invalid
lines or unresolved procedure calls with the method SetEngineAttribute (see section 20.1.1 on page 154).
In the example mfc\exec_procedures_mt_mfc , three threads execute HDevelop procedures for image acquisi-
tion, data code reading, and visualization in parallel (see figure 18.7 on page 129). Please have a look at the example
source files (in the directory mfc\exec_procedures_mt_mfc\source\) to see how the threads synchronize their
input and output data.
Figure 18.5: Content of the exception if an input parameter was not initialized.
18.3 Using the Just-in-time Compiler with HDevEngine/C++ 129
Figure 18.6: Content of the exception if an error occurred in a HALCON operator call.
HDevEngine
Figure 18.7: Example program with three threads performing image acquisition, data code reading, and visualization
in parallel.
The example exec_programs_mt (source file exec_programs_mt.cpp) shows how one or several different HDe-
velop programs can be executed in different threads in parallel. Note that it is kept very general and does not realize
a specific application.
The HDevelop program(s) must be passed as command line arguments. Optionally, you can pass for every program
the number of threads and/or how often the program should be performed consecutively within each thread. The
command line parameters are explained when calling the executable without parameters.
The example application use_vector_variables shows how to load and execute an HDevelop program that
contains vector variables in HDevengine/C++. In the example two vectors are used for processing: one con-
taining the input images and one containing scaling factors. When executing the program the gray values of
the input images are scaled according to the scaling factors. Please have a look at the example source file
use_vector_variables.cpp for more details on how to work with vector variables in HDevengine/C++.
The just-in-time compilation of procedures needs to be enabled in your instance of the HDevEngine class:
130 HDevEngine in C++ Applications
Procedures (and procedures referenced by it) are compiled at the moment a corresponding instance of
HDevProcedureCall or HDevProgramCall is created.
You can also explicitly pre-compile all used procedures of a HDevelop program or procedure using the method
CompileUsedProcedures of HDevProgram or HDevProcedure, respectively.
In the following example, all used procedures of a procedure call are just-in-time compiled:
HDevProgram my_program(program_path.c_str());
HDevProcedure proc_fib(my_program,"fib");
...
proc_fib.CompileUsedProcedures();
HDevEngine in .NET Applications 131
Chapter 19
This chapter explains how to use HDevEngine in C# and Visual Basic .NET applications. Section 19.1 on page 131
quickly summarizes some basic information about creating HDevEngine applications with Visual Studio .NET and
Visual Studio 2005. Section 19.2 on page 131 then explains how to use HDevEngine/.NET based on examples.
19.1 Basics
HDevEngine
• specify the namespace with the following line (also see section 10.2.3 on page 62):
using HalconDotNet;
HDevEngine XL applications: If you want to use HDevEngine/.NET XL, you must add the XL versions of the
HALCON/.NET and HDevEngine/.NET assembly instead.
A short reference of the C++ classes for the HDevEngine can be found in section 20.1 on page 153. The .NET
classes are very similar; their exact definition can be seen in the online help of Visual Studio (see section 10.5.1 on
page 65).
19.2 Examples
This section explains how to employ HDevEngine/.NET based on example applications for C# and Visual Ba-
sic .NET, which reside in the subdirectories %HALCONEXAMPLES%\hdevengine\c# and %HALCONEXAMPLES%\
hdevengine\vb.net. In the following, we describe only the C# examples; the Visual Basic .NET versions are
identical except for the standard differences between the two languages. Furthermore, in contrast to the C# ver-
sions, the Visual Basic .NET versions do not contain support for Linux.
• executing an HDevelop program (section 19.2.1 on page 132),
• executing HDevelop procedures (section 19.2.2 on page 134), and
• display operators (section 19.2.3 on page 138),
• error handling (section 19.2.4 on page 139), and
• multithreading (section 19.2.5 on page 141).
132 HDevEngine in .NET Applications
In this section, we explain how to load and execute an HDevelop program with HDevEngine. The code fragments
stem from the example application ExecProgram, which checks the boundary of a plastic part for fins. Figure 19.1
on page 132 shows a screenshot of the application; it contains two buttons to load and execute the HDevelop
program.
Upon loading the form, we store the path to the HDevelop program and set the external procedure path with the
method SetProcedurePath:
String ProgramPathString;
ProgramPathString = halconExamples +
@"\hdevengine\hdevelop\fin_detection.hdev";
if (!HalconAPI.isWindows)
{
ProcedurePath = ProcedurePath.Replace('\\', '/');
ProgramPathString = ProgramPathString.Replace('\\', '/');
}
MyEngine.SetProcedurePath(ProcedurePath);
}
Note that the latter is only necessary if the HDevelop program calls external procedures.
When you click the button to load the HDevelop program, an instance of the class HDevProgram is created, with
the path of the program as parameter. Furthermore, an instance of HDevProgramCall is created for later use. Note
that the working directory will be changed if a program is loaded.
Exceptions occurring in the constructors, e.g., because the file name was not specified correctly, are handled with
the standard C# error handling mechanism:
19.2 Examples 133
More information on error handling can be found in section 19.2.4 on page 139.
When you click the button to execute the program, the method Execute is called:
HDevEngine
try
{
ProgramCall.Execute();
}
catch (HDevEngineException Ex)
{
MessageBox.Show(Ex.Message, "HDevEngine Exception");
return;
}
}
catch (Exception)
{
}
}
That’s all you need to do to execute an HDevelop program. You can also access its “results”, i.e., its variables
with the method GetCtrlVarTuple. In the example program, the area of the extracted fin is queried and then
displayed:
double FinArea;
FinArea = ProgramCall.GetCtrlVarTuple("FinArea");
Window.SetTposition(150, 20);
Window.WriteString("Fin Area: ");
Note that program variables can only be accessed when the program has terminated.
134 HDevEngine in .NET Applications
Figure 19.2: Executing an external HDevelop procedure that detects fins on a boundary.
How to display results while the program is running is described in section 19.2.3 on page 138.
In this section, we explain how to load and execute an external HDevelop procedure with HDevEngine. The code
fragments in the following stem from the example application ExecExtProc, which, like the example described
in the previous section, checks the boundary of a plastic part for fins. Figure 19.2 on page 134 shows a screenshot
of the application; it contains two buttons to load and execute the HDevelop procedure.
In contrast to the previous example, the result display is programmed explicitly instead of relying on the internal
display operators.
As when executing an HDevelop program, we create a global instance of the main HDevEngine class HDevEngine
and set the external procedure path with the method SetProcedurePath upon loading the form (code for con-
structing the path omitted). If the external procedure is from a procedure library, the external procedure path may
include the name of the library file.
In contrast to the C++ version of this example application, we want to display the results not in a free-floating
graphics window, but within the form, i.e, inside an instance of HSmartWindowControl (also see section 10.4 on
page 63 and section 10.8 on page 75). For calling the HALCON operators, we declare a global variable of the
class HWindow for the underlying HALCON window; upon loading the form, we set this variable to the HALCON
window in the HSmartWindowControl and initialize the window:
19.2 Examples 135
Window.SetDraw("margin");
Window.SetLineWidth(4);
}
When you click the button Load, the HDevelop procedure is loaded with the constructor of the class
HDevProcedure, specifying the name of the procedure, and a corresponding procedure call is created as an in-
stance of the class HDevProcedureCall. Exceptions occurring in the constructors, e.g., because the file name or
the procedure path was not specified correctly, are handled with the standard C# error handling mechanism. More
information on error handling can be found in section 19.2.4 on page 139.
HDevEngine
}
Executing a procedure consists of multiple steps. First, we load an example image sequence:
Each image should now be processed by the procedure, which has the following signature, i.e., it expects an image
as (iconic) input parameter and returns the detected fin region and its area as iconic and control output parameter,
respectively:
We pass the image as an input object by storing it in the instance of HDevProcedureCall with the method
SetInputIconicParamObject. Which parameter to set is specified via its name (as an alternative, you can
specify it via its index):
136 HDevEngine in .NET Applications
ProcCall.SetInputIconicParamObject("Image", Image);
As as alternative to passing parameters, you can also use global variables in HDevEngine (compare
the HDevelop User’s Guide, section 8.3.2 on page 275). You set the value of a global variable with
the methods SetGlobalIconicVarObject or SetGlobalCtrlVarTuple and query it with the methods
GetGlobalIconicVarObject and GetGlobalCtrlVarTuple.
ProcCall.Execute();
If the procedure was executed successfully, we can access its results, i.e., the fin region and its area, with the
methods GetOutputIconicParamRegion and GetOutputCtrlParamTuple of the class HDevProcedureCall;
again, you can specify the parameter via its name or index. Note that you can get iconic output ob-
jects either as instances of the corresponding class (here, HRegion) or as instance of HObject by using
GetOutputIconicParamObject.
FinRegion = ProcCall.GetOutputIconicParamRegion("FinRegion");
FinArea = ProcCall.GetOutputCtrlParamTuple("FinArea");
Image.DispObj(Window);
Window.SetColor("red");
Window.DispObj(FinRegion);
Window.SetColor("white");
Window.SetTposition(150, 20);
Window.WriteString("FinArea: " + FinArea.D);
}
The example application ExecProcedures executes local and external HDevelop procedures with HDevEngine.
It mimics the behavior of the HDevelop program described in section 19.2.1 on page 132. The display of results
is partly programmed explicitly and partly delegated to an HDevelop procedure, using the implementation of the
internal display operators described in section 19.2.3 on page 138. Figure 19.3 on page 137 shows a screenshot of
the application.
In the following, we briefly describe parts of the code.
19.2 Examples 137
Local and external procedures are created and executed in exactly the same way. The only difference is that in
order to use a local procedure, you must load the program it is contained in, whereas to load external procedures
you must set the procedure path. In the example, the image processing procedure is local, the other external. Note
that the code for constructing the program and procedure path is omitted.
HDevEngine
{
try
{
HDevProgram Program = new HDevProgram(ProgramPathString);
One of the procedures opens the image acquisition device. It returns the corresponding handle, which we store in
an instance of the class HFramegrabber.
HFramegrabber Framegrabber;
In the example application, the device is closed when the application terminates and calls the finalizer of the class
HFramegrabber, which in turn calls the operator CloseFramegrabber. If you use an HDevelop procedure for
138 HDevEngine in .NET Applications
closing the connection to the device, you would invalidate the handle so that the finalizer raises an exception.
As in the previous example, the results of image processing (button Process Image) are displayed “manually”
by calling HALCON/.NET operators. In contrast, when you click the button Visualize Details, an HDevelop
procedure is executed that zooms onto the extracted fin. For this, we pass an implementation of HDevelop’s
internal display operators (see section 19.2.3 on page 138 for more information about the implementation classes)
and remove it again after the procedure has been executed.
The instance of the implementation class is initialized with the HALCON window of the form.
If the class HDevOpMultiWindowImpl is initialized without specifying the window, a new HALCON window will
open automatically to emulate the behavior of HDevelop. Consequently, using the operator dev_open_window
in your HDevelop program or procedure will open another window. The newly opened window is set active
automatically.
19.2.3 Display
In contrast to the C++ version of HDevEngine, HDevEngine/.NET already provides convenience implementations
of HDevelop’s internal display operators in form of two classes:
• HDevOpFixedWindowImpl directs all display operators to a single graphics window (passed in the construc-
tor), even if the HDevelop program or procedure uses multiple windows.
• HDevOpMultiWindowImpl can handle multiple graphics windows. You can pass an arbitrary number of
graphics windows in the constructor; if the HDevelop program or procedure uses more than them, HDevEn-
gine opens additional free-floating windows.
! Please note that these classes must not be used in multithreaded applications because they are not reentrant. If
you need a reentrant version, please discuss your application requirements with your local distributor.
The example program ExecProgram uses HDevOpMultiWindowImpl. To use this class (or
HDevOpFixedWindowImpl), you pass an instance of it to HDevEngine with the method :
MyEngine.SetHDevOperators(new HDevOpMultiWindowImpl(Window));
}
If your application has special display requirements that are not satisfied by the two classes, you can provide
your own implementation of the display operators similar to the C++ version of HDevelop (see section 18.2.3
19.2 Examples 139
on page 125) by creating a class implementing the interface IHDevOperators and overloading its methods
DevOpenWindow, DevDisplay, etc.
Please note that currently you cannot use any form of display operator implementation with Mono (see sec-
tion 11.2.1 on page 81).
In this section, we take a closer look at exceptions in HDevEngine. The code fragments in the following stem
from the example application ErrorHandling, which provokes and catches different types of exceptions when
you press some buttons. Figure 19.4 on page 139 shows a screenshot of the application.
HDevEngine throws exceptions as instances of the class HDevEngineException, which contains the type (cate-
gory) of the exception, a message describing the exception, and, depending on the exception type, information like
the name of the executed procedure or the HALCON error code (also see section 20.1.7 on page 166).
In the example application, the following procedure displays all the information contained in
HDevEngineException in a message box:
HDevEngine
", program line: <" + Ex.LineText + ">" +
", line number: <" + Ex.LineNumber + ">" +
", HALCON Error Number: <" + Ex.HalconError + ">";
MessageBox.Show(FullMessage, Title);
}
This procedure is called when an exception occurs; note that the example applications described in the previous
sections only display the exception message.
try
{
HDevProgram Program = new HDevProgram(ProgramPathString);
new HDevProgramCall(Program);
}
Figure 19.5 on page 140 displays an exception that occurred because the application tried to load a non-existing
HDevelop program (category ExceptionFile). As you can see, only the message contains useful information in
this case.
The next exception occurs when executing a procedure in which an input parameter is not initialized (category
ExceptionInpNotInit):
140 HDevEngine in .NET Applications
Figure 19.5: Content of the exception if an HDevelop program could not be loaded.
Figure 19.6 on page 140 displays the content of the exception, which now contains very detailed information about
where the error occurred and why.
Figure 19.6: Content of the exception if an input parameter was not initialized.
The final exception is provoked by executing a procedure in which the call to the operator closing_circle fails
because the third parameter is not valid (category ExceptionCall).
Figure 19.7: Content of the exception if an error occurred in a HALCON operator call.
HDevEngine
of the corresponding HDevProgramCall.
• External procedure path and the implementation of HDevelop’s display operators are always set glob-
ally for all instances of HDevEngine. We recommend to set them via a separate HDevEngine instance to
keep the code more readable.
• Because the implementation of HDevelop’s display operators can only be set globally, it must be thread-
safe and reentrant. The classes HDevOpFixedWindowImpl and HDevOpMultiWindowImpl described in
section 18.2.3 on page 125 do not fulfill this condition. For a reentrant version please discuss your application
requirements with your local distributor.
The example application MultiThreading presented in this section exploits multi-core or multi-processor systems
by executing the same HDevelop procedure (task) in parallel by two threads. The procedure finds bottle caps using
shape-based matching.
Figure 19.8 on page 142 shows an overview of the structure of the application. It consists of four threads: The
main thread (i.e., the form) is in charge of the graphical user interface (GUI), which is depicted in figure 19.9 on
page 142. It consists of a HALCON window for the display of results and buttons to initialize, start, and stop the
application.
The main thread also initializes the application by training the shape model via an HDevelop procedure and by
creating and initializing the other three threads: two processing threads and the so-called control thread, whichs
controls the two processing threads.
The control thread acquires the images and passes them to the processing threads, which then process the images
and pass back the results. The control thread collects the results, but does not display them itself, because all
activities in the HALCON window must be performed by the thread that created it, i.e., the main thread.
Now, we take a closer look at the corresponding code. Please note that we do not show all details; in particular,
error handling, and termination including memory management are left out.
142 HDevEngine in .NET Applications
Main Thread
(MultiThreadingForm)
Control Thread Processing Thread
GUI (buttons, HALCON window)
(ControlThread) (EngineThread)
initialize application
acquire images
pass image to processing thread
process image
pass results
collect results
delegate result display
display results
Initialization
The application is initialized in the event handler of the Init button (file: MultiThreadingForm.cs).
HOperatorSet.SetSystem("parallelize_operators", "false");
First, the automatic operator parallelization is switched off, otherwise the two mechanisms (multithreading and
operator parallelization) would use more than the available number of cores / processors and thus slow down
the application instead of speeding it up (see the style guide in section 2.2.2 on page 15). If you have a system
with more than two cores or processors, you can consider to allocate some of them to the automatic operator
parallelization as described in section 2.5.1 on page 18.
Step 2: Set external procedure path
Then, we create an instance of HDevEngine and set the path for searching the HDevelop procedures (code for
constructing the path omitted). If the external procedure is from a procedure library, the external procedure path
may include the name of the library file.
19.2 Examples 143
HDevProcedureCall ProcTrain;
ModelID = ProcTrain.GetOutputCtrlParamTuple("ModelID");
ModelContours = ProcTrain.GetOutputIconicParamXld("ModelContours");
HDevEngine
public class EngineThread
{
Thread WorkerObject = null;
HDevProcedureCall ProcCall;
HTuple ModelID;
HXLD ModelContours;
public AutoResetEvent EngineIsReady;
The main thread creates and initializes two instances of this class and also stores their events (file:
MultiThreadingForm.cs).
An EngineThread initializes itself by creating the procedure call for detecting the caps in the images. Because
the input parameters of the procedure that concern the shape model are the same for each call, they can be set once
in advance (file: EngineThread.cs).
Image Processing
When you click the Run button, the application starts to process images in a loop.
Step 1: Starting the processing threads and the control thread
First, the main thread starts the processing engines (file: MultiThreadingForm.cs).
The corresponding method creates and starts their thread and sets the “ready” signal (file: EngineThread.cs).
Then, the main thread starts the control thread (file: MultiThreadingForm.cs):
Image = AcqHandle.GrabImageAsync(-1);
WorkerEngine.SetImage(Image);
Then, it acquires the next image and passes it to the engine, which stores it in a member variable (file:
EngineThread.cs).
HDevEngine
public void Process()
{
while (!DelegatedStopEvent.WaitOne(0, true))
{
if (InputImage == null)
continue;
ProcCall.SetInputIconicParamObject("Image", InputImage);
ProcCall.Execute();
After executing the procedure, the processing thread accesses its results and stores them in a new instance of the
result class (“result container”), together with the processed image.
146 HDevEngine in .NET Applications
ResultContainer Result;
HTuple ResultTuple;
The processing thread then passes the result container to the control thread by appending it to a list.
ResultMutex.WaitOne();
ResultList.Add(Result);
ResultMutex.ReleaseMutex();
This list is a member variable of the main thread (file: MultiThreadingForm.cs). It is protected by a mutex so
that the threads can access it safely.
public MultiThreadingForm()
{
ResultDataMutex = new Mutex();
ResultList = new ArrayList();
}
The processing threads store references to the list and to the mutex in own member variables (file:
EngineThread.cs).
ArrayList ResultList;
Mutex ResultMutex;
InputImage = null;
this.EngineIsReady.Set();
Result Display
Step 1: Checking whether new results are available
Let’s return to the action method (Run) of the control thread (file: MultiThreadingForm.cs). After triggering a
processing thread by passing the image to process, it checks whether the result list contains new items.
ResultDataMutex.WaitOne();
Count = ResultList.Count;
ResultDataMutex.ReleaseMutex();
19.2 Examples 147
public MultiThreadingForm()
{
DelegatedDisplay = new FuncDelegate(DisplayResults);
}
Note that, since HALCON 12, all HALCON visualization operators are automatically delegated to the correct
thread as described in chapter section 2.3 on page 16.
Step 3: Displaying the results
The actual display is performed by the method DisplayResults. Each time it is called, it removes an item from
the result list and displays the processed image with the contours of the found cap. Then, it frees the corresponding
HALCON-internal memory.
HDevEngine
Window.ClearWindow();
Window.DispImage(Result.InputImage);
Window.DispObj(Result.FoundContours);
Result.InputImage.Dispose();
Result.FoundContours.Dispose();
}
In contrast to the previous section, the example application MultiThreadingTwoWindows presented here executes
different HDevelop procedures (tasks) in parallel by two threads. One task is to find bottle caps using shape-based
matching, the other to read ECC 200 data codes.
Figure 19.10 on page 148 shows an overview of the structure of the application. Like the application described in
the previous section, it consists of four threads: The main thread (i.e., the form) is in charge of the graphical user
interface (GUI), which is depicted in figure 19.9 on page 142. It consists of a HALCON window for the display of
results and buttons to initialize, start, and stop the application.
The main thread also initializes the application by creating and initializing the other three threads: two processing
threads and the so-called control thread, whichs controls the two processing threads. In contrast to the previous
application, here the processing threads initialize the image processing tasks by training the shape model and the
data code model, respectively, via HDevelop procedures.
The control thread acquires the images and passes them to the processing threads, which then process the image and
pass back the results. The control thread collects the results, but does not display them itself, because all activities
in the HALCON window must be performed by the thread that created it, i.e., the main thread. In contrast to the
previous application the results of the two tasks are displayed in two separate windows.
Below, we take a closer look at the corresponding code, restricting ourselves, however, to the parts that are diferent
to the previous application.
148 HDevEngine in .NET Applications
Main Thread
Processing Thread
(MultiThreadingTwoWindowsForm)
Control Thread (EngineThread)
GUI (buttons, HALCON window)
(ControlThread)
initialize application initialize task
acquire images
pass image to processing thread
process image
pass results
collect results
delegate result display
display results
Initialization
As in the previous example, the application is initialized in the event handler of the Init button (file:
MultiThreadingTwoWindowsForm.cs).
Step 1: Create and initialize the processing engines
The processing engines are created and initialized similarly to the previous example, with some exceptions: First,
the shape and the data code model are now trained by the processing threads instead of the control thread (see the
step below). Secondly, the processing engines now also have a variable that indicates “their” HALCON window
(file: EngineThread.cs).
19.2 Examples 149
The control thread sets this variable after creating the engines (file: MultiThreadingTwoWindowsForm.cs).
WorkerEngine1.Init("shape");
...
WorkerEngine2.Init("datacode");
The HDevelop procedures for training the models and for performing the image processing have similar names for
the two tasks, so that their names can be generated automatically (file: EngineThread.cs). The task name itself
is stored in a variable of the class EngineThread.
HDevEngine
HDevProcedureCall ProcCall;
string Task;
HTuple ModelID;
HXLD ModelContours;
...
this.Task = Task;
Then, the model of the shape or datacode, respectively, is trained by executing the corresponding HDevelop pro-
cedure and the returned model data is stored in variables of the class.
Image Processing
Step 1: Triggering the processing threads
The control thread’s action is contained in the method Run (file: MultiThreadingTwoWindowsForm.cs). As
long as the Stop is not pressed, it checks whether the processing engines are ready and, if this is the case, acquires
and passes images..
while (!StopEventHandle.WaitOne(0,true))
{
if (Engine1Ready.WaitOne(0,true))
{
Image = AcqHandle1.GrabImageAsync(-1);
WorkerEngine1.SetImage(Image);
}
if (Engine2Ready.WaitOne(0,true))
{
Image = AcqHandle2.GrabImageAsync(-1);
WorkerEngine2.SetImage(Image);
}
After executing the procedure, the processing thread accesses its results and stores them in a new instance of the
result container, together with the processed image and the window index.
19.2 Examples 151
Result Display
As in the previous example, the display of results is performed by the main thread in the method ResultDisplay
(file: MultiThreadingTwoWindowsForm.cs). The main difference is that the display now is switched between
the two HALCON windows, based on the variable in the result container.
if (Result.WindowIndex == 1)
{
HDevEngine
Window = Window1;
}
else
{
Window = Window2;
}
Furthermore, the display method now checks the success of the image processing to avoid accessing non-existing
result elements. For both tasks, the resulting contours, i.e., the found shape or data code region, respectively, are
displayed. For the data code task, also the read code is displayed.
152 HDevEngine in .NET Applications
Window.ClearWindow();
Window.DispImage(Result.InputImage);
if (Result.DetectionSuccessful)
{
Window.DispObj(Result.FoundContours);
// additional display for data code result: code
if (Result.WindowIndex == 2)
{
Row = (int) Result.ResultData[0].D;
Col = (int) Result.ResultData[1].D;
Window.SetTposition(Row,Col);
Window.WriteString((string) Result.ResultData[2].S);
}
}
else
{
Window.SetColor("red");
Window.SetTposition(20, 20);
Window.WriteString("Detection failed!");
Window.SetColor("green");
}
The example application UseVectorVariables shows how to load and execute an HDevelop example that con-
tains vector variables in HDevengine/C#. In the example two vectors are used for processing: one containing the
input images and one containing scaling factors. When executing the program the gray values of the input images
are scaled according to the scaling factors. Please have a look at the source file UseVectorVariablesForm.cs
for more details on how to work with vector variables in HDevengine/.NET.
The just-in-time compilation of procedures needs to be enabled in your instance of the HDevEngine class:
...
Engine = new HDevEngine();
Procedures (and procedures referenced by it) are compiled at the moment a corresponding instance of
HDevProcedureCall or HDevProgramCall is created.
You can also explicitly pre-compile all used procedures of a HDevelop program or procedure using the method
CompileUsedProcedures of HDevProgram or HDevProcedure, respectively.
In the following example, all used procedures of a procedure call are just-in-time compiled:
Chapter 20
General Information
This chapter contains an overview about the main classes of HDevEngine and their methods (section 20.1 on
page 153) and miscellaneous application tips (section 20.3 on page 169). Remote debugging of HDevEngine
applications from HDevelop is described in section 20.2 on page 167.
Note in the following, we print only the declaration of the classes for HDevEngine/C++. In the other variants of
HDevEngine, the methods and properties have the same names.
HDevEngine
154 General Information
20.1.1 HDevEngine
.NET: HDevEngine
*****************************************************************************
** class HDevEngine
**===========================================================================
** Class for managing global engine settings:
** + external procedure path
** + implementation of dev_ operators (HDevOperatorImpl)
** + Attention: all changes made to one HDevEngine instance all global
** for all .dev programs or .dvp procedure that are executed in one
** application
*****************************************************************************
*****************************************************************************/
class LIntExport HDevEngine
{
public:
HDevEngine();
HDevEngine
// procedure is reloaded explicitly. The appropriate calls must be
// recreated or reassigned by the reloaded program or procedure.)
// - additional calls of SetProcedurePath will remove paths set before
// and unload all external procedures
void SetProcedurePath(const char* path);
void AddProcedurePath(const char* path);
#ifdef _WIN32
void SetProcedurePath(const wchar_t* path);
void AddProcedurePath(const wchar_t* path);
#endif
// Get names of all available external procedures
HalconCpp::HTuple GetProcedureNames() const;
// Get names of all loaded external procedures
HalconCpp::HTuple GetLoadedProcedureNames() const;
// Unload a specific procedure <proc_name>
void UnloadProcedure(const char* proc_name);
// Unload all external procedures
void UnloadAllProcedures();
20.1.2 HDevProgram
.NET: HDevProgram
*****************************************************************************
** class HDevProgram
**===========================================================================
** Class for managing HDevelop programs
*****************************************************************************
class LIntExport HDevProgram
{
public:
// Create a program from a .dev program file
HDevProgram(const char* file_name=NULL);
#ifdef _WIN32
HDevProgram(const wchar_t* file_name);
#endif
// Copy constructor
HDevProgram(const HDevProgram& hdev_prog);
HDevProgram(const Data& data);
// Assignment operation
HDevProgram& operator=(const HDevProgram& hdev_prog);
// Destructor
virtual ~HDevProgram();
#ifdef _WIN32
HDevEngine
void LoadProgram(const wchar_t* file_name);
#endif
// Get the names of all local and the used external procedures
HalconCpp::HTuple GetUsedProcedureNames() const;
HalconCpp::HTuple GetLocalProcedureNames() const;
// Compile all procedures that are used by the program and that can be
// compiled with a just-in-time compiler.
// The method returns true when all used procedures could be compiled by the
// just-in-time compiler.
// Procedures that could not be compiled are called normally by the
// HDevEngine interpreter.
// To check which procedure could not be compiled and what the reason is for
// that start HDevelop and check there the compilation states.
bool CompileUsedProcedures();
// get some information about the variables of the program's main procedure:
// - get the variable names as a tuple
HalconCpp::HTuple GetIconicVarNames() const;
HalconCpp::HTuple GetCtrlVarNames() const;
20.1.3 HDevProgramCall
.NET: HDevProgramCall
*****************************************************************************
** class HDevProgramCall
**===========================================================================
** Class for managing the execution of an HDevelop program
*****************************************************************************
class LIntExport HDevProgramCall
{
public:
// Create an empty HDevelop program call instance
HDevProgramCall();
// Create an HDevelop program call from a program
HDevProgramCall(const HDevProgram& prog);
// Copy constructor
HDevProgramCall(const HDevProgramCall& hdev_prog_call);
HDevProgramCall(const Data& data);
// Assignment operation
HDevProgramCall& operator=(const HDevProgramCall& hdev_prog_call);
// Destructor
virtual ~HDevProgramCall();
// Execute program
void Execute();
HDevEngine
void SetWaitForDebugConnection(bool wait_once);
20.1.4 HDevProcedure
.NET: HDevProcedure
*****************************************************************************
** class HDevProcedure
**===========================================================================
** Class for managing HDevelop procedures
*****************************************************************************
class LIntExport HDevProcedure
{
public:
// Create HDevelop procedure from external or local procedure
HDevProcedure(const char* proc_name=NULL);
HDevProcedure(const char* prog_name, const char* proc_name);
HDevProcedure(const HDevProgram& prog, const char* proc_name);
#ifdef _WIN32
HDevProcedure(const wchar_t* prog_name, const char* proc_name);
#endif
// Copy constructor
HDevProcedure(const HDevProcedure& hdev_proc);
HDevProcedure(const Data& data);
// Assignment operation
HDevProcedure& operator=(const HDevProcedure& proc);
// Destructor
~HDevProcedure();
HDevEngine
#ifdef _WIN32
void LoadProcedure(const wchar_t* prog_name, const char* proc_name);
#endif
// Compile all procedures that are used by the procedure and that can be
// compiled with a just-in-time compiler.
// The method returns true when all used procedures could be compiled by the
// just-in-time compiler.
// Procedures that could not be compiled are called normally by the
// HDevEngine interpreter.
// To check which procedure could not be compiled and what the reason is for
// that start HDevelop and check there the compilation states.
bool CompileUsedProcedures();
HDevEngine
164 General Information
20.1.5 HDevProcedureCall
.NET: HDevProcedureCall
*****************************************************************************
** class HDevProcedureCall
**===========================================================================
** Class for executing an HDevelop procedure and managing the parameter
** values
*****************************************************************************
class LIntExport HDevProcedureCall
{
public:
// Create an empty HDevelop procedure call instance
HDevProcedureCall();
// Create HDevelop procedure call instance
HDevProcedureCall(const HDevProcedure& hdev_proc);
// Copy constructor
HDevProcedureCall(const HDevProcedureCall& hdev_proc_call);
HDevProcedureCall(const Data& data);
// Assignment operation
HDevProcedureCall& operator=(const HDevProcedureCall& hdev_proc_call);
// Destructor
~HDevProcedureCall();
// Execute program
void Execute();
HDevEngine
// These methods are provided for efficiency:
// the results are copied directly into the tuple variable provided by
// the user without additional copying
void GetOutputCtrlParamTuple(int par_idx, HalconCpp::HTuple* tuple) const;
void GetOutputCtrlParamTuple(const char* par_name,
HalconCpp::HTuple* tuple) const;
};
Note that HDevEngine/.NET provides additional methods that return iconic output parameters of a pro-
cedure call in the corresponding class (GetOutputIconicParamImage, GetOutputIconicParamRegion,
GetOutputIconicParamXld).
166 General Information
20.1.6 HDevOperatorImplCpp
.NET: IHDevOperators
*****************************************************************************
** class HDevOperatorImplCpp
**===========================================================================
** Class for the implemention of HDevelop internal operators
*****************************************************************************
class LIntExport HDevOperatorImplCpp
{
public:
HDevOperatorImplCpp();
// Copy constructor
HDevOperatorImplCpp(const HDevOperatorImplCpp& hdev_op_impl);
HDevOperatorImplCpp(const Data& data);
// Assignment operation
HDevOperatorImplCpp& operator=(const HDevOperatorImplCpp& hdev_op_impl);
// Destructor
virtual ~HDevOperatorImplCpp();
20.1.7 HDevEngineException
.NET: HDevEngineException
20.2 Debugging HDevEngine from HDevelop 167
*****************************************************************************
** class HDevEngineException
**===========================================================================
** Class for HDevelop engine exceptions
*****************************************************************************
class LIntExport HDevEngineException
{
public:
// Exception categories
enum ExceptionCategory
{
Exception, // Generic
ExceptionInpNotInit, // Error input parameters not initialized
ExceptionCall, // Error HALCON or HDevelop operator call
ExceptionFile // Error opening or reading HDevelop file
};
// Error text
const char* Message() const;
// Category of exception
HDevEngine
ExceptionCategory Category() const;
const char* CategoryText() const;
// Name of executed procedure
const char* ExecProcedureName() const;
// Number of executed procedure or operator program line
int ProgLineNum() const;
// Name of executed procedure or operator program line
const char* ProgLineName() const;
// HALCON error code
Herror HalconErrorCode() const;
HDevEngine applications can be debugged remotely using HDevelop. The application must explicitly enable
remote debugging itself. This will start a debug server, which accepts debug connections from HDevelop. How to
attach to an application from HDevelop is described in the HDevelop User’s Guide, chapter 9 on page 317. The
following sections describe remote debugging from the perspective of HDevEngine. Two of the supplied example
programs illustrate how to deploy the debug server in an application:
• hdevengine/c#/UseDebugServer
• hdevengine/cpp/use_debug_server
168 General Information
HDevEngine provides two member functions to start and stop the debug server.
MyEngine.StartDebugServer();
...
MyEngine.StopDebugServer();
Usually, HDevEngine executes HDevelop code continuously without any interruption. However, once the debug
server has started, the execution of HDevelop code can be interrupted for debugging purposes.
There are multiple ways for HDevEngine to enter a stopped state. The first two are available through the API.
They work regardless of whether HDevelop is actually attached. Please note that the only way to continue program
execution is to actually attach HDevelop to the debug server and control the execution from there.
Other ways to stop the program execution are triggered only if HDevelop is attached to the debug server:
• A Stop command (F9 ) is sent from HDevelop.
• An activated break point on a program line or variable is reached by HDevEngine.
20.3 Tips and Tricks 169
• An unhandled error occurs. Normally, HDevEngine would throw a HDevException in this case, but in
debug mode a notification is sent out to HDevelop so that the error condition can be examined there. The
delayed exception will be thrown when the program execution continues.
Regardless of the reason the stopped state is always global, i.e., other application threads will also stop when
executing HDevelop code.
Like any remotely accessible server, careful attention must be paid in order to prevent unauthorized access to the
debug server. Although the firewall must be configured to allow connections to the configured port, it is your
responsibility to limit the access to authorized clients only.
As a minimal security measure, always set up a password for the debug server. Please note that the debug server
itself provides no measures against brute-force or denial-of-service attacks.
Note the following if the debug server is running and no password is set:
Apart from the transmission of passwords, the communication between HDevelop and the debug server is not
encrypted. Protected procedures are transmitted in their encrypted binary form. If you worry about other sensitive
data like images, you should use a VPN (e.g., an SSH tunnel) when connecting from the outside to the local
network.
20.2.4 Limitations
HDevEngine
• Subthreads started with par_start cannot be debugged.
• JIT-compiled procedures cannot be debugged.
Further limitations of remote debugging from the HDevelop side are listed in the HDevelop User’s Guide, sec-
tion 9.9 on page 320.
20.3.1 Troubleshooting
? Executed program or procedure raises exception for display operators like set_tposition when not
using implementation of display operators
If you are not using an implementation of HDevelop’s internal display operators (dev_*), calls to these
operators in the executed HDevelop program or procedure are simply ignored. However, if the program or
procedure contains other, “external” display operators like set_tposition or write_string, which need
a window handle as input parameter, the program / procedure will raise an exception at this operator if the
window handle has not been instantiated.
Typically, this problem will not arise when executing programs, because you will in most cases use an
implementation of the display operators. When executing procedures, we recommend to leave out the
external display operators that use window handles. If this is not possible, you could place them in a
separate procedure and use the implementation of display operators for just this procedure. Alternatively,
initialize the window handle with a value like -1 and test it before executing the external display operators.
To ensure that programs developed with HDevelop can be executed with HDevEngine without any further action,
all standard procedures (see the HDevelop User’s Guide, section 5.4 on page 41) are automatically loaded when
HDevEngine is started.
In most applications there is no need to delete loaded HDevelop procedures explicitly using UnloadProcedure.
A reason might be to free memory.
Please note that when creating a procedure with the class HDevProcedure, the procedure is loaded together with
all the procedures it uses. In contrast, UnloadProcedure deletes only the specified procedure. To delete the auto-
matically loaded procedures, you can query their names using GetLoadedProcedureNames and then delete them
(if you are sure that they are not used by another loaded procedure!), or you can use UnloadAllProcedures
to unload all external procedures. Note that after calling UnloadProcedure or UnloadAllProcedures,
GetProcedureNames still returns the names of the unloaded procedures.
Index 171
Index
Index
create C application (HALCON/C), 105 132, 133
create C++ application (HALCON/C++), 47 execute HDevelop program (HDevEngine/C++),
create C# application (HALCON/.NET), 59 120, 121
create executable (HALCON/C) execute local HDevelop procedure (HDevEn-
Linux, 107 gine/.NET), 136
Windows, 107 execute local HDevelop procedure (HDevEn-
create executable (Halcon/C++) gine/C++), 124
Linux, 50
macOS, 51 finalizers (HALCON/.NET), 67
Windows, 49
create executable (HDevEngine/C++), 119 garbage collection (HALCON/.NET), 68
create tuple (HALCON/.NET), 72 get tuple element (HALCON/.NET), 71
create tuple (HALCON/C), 93 get tuple element (HALCON/C), 93
create Visual Basic .NET application (HAL-
HALCON language interface for C applications, 11
CON/.NET), 59
HALCON language interface for C++ applications,
customize Visual Studio for HALCON/.NET, 61
11
customize visualization (HALCON/.NET), 63
HALCON language interface for C# applications, 11
declare class instance (HALCON/.NET), 66 HALCON language interface for managed C++ ap-
deploy HALCON/.NET application, 76 plications, 11
Linux, 81 HALCON language interface for Visual Basic .NET
applications, 11
172 Index
vectors (HALCON/.NET), 74
vectors (HALCON/C), 95
vectors (HALCON/C++), 44
Visual Basic .NET application
example, 80
visualization (HALCON/.NET), 75
Index