You are here: Start » Programming Reference » Macrofilters

# Macrofilters

Read before: Introduction to Data Flow Programming.

For information about creating macrofilter in the user interface, please refer to Creating Macrofilters.

## Macrofilter Structures

There are three possible structures of macrofilters which play three different roles in the programs:

• Steps
• Variant Steps

## Steps

Step is the most basic macrofilter structure. Its main purpose is to make programs clean and organized.

A macrofilter of this structure simply separates a sequence of several filters that can be used as one block in many places of the program. It works exactly as if its filters were expanded in the place of each macrofilter's instance. Consequently:

• The state of the contained filters and registers is preserved between consecutive invocations.
• If a loop generator is inserted to a Step macrofilter, then this step becomes a loop generator as the whole.
• If a loop accumulator is inserted to a Step macrofilter, then this step becomes a loop accumulator as the whole.

## Variant Steps

Variant macrofilters are similar to Steps, but they can have multiple alternative execution paths. Each of the paths is called a variant. At each invocation exactly one of the variants is executed – the one that is chosen depends on the value of the forking input or register (depicted with the icon), which is compared against the labels of the variants.

The type of the forking port and the labels can be: Bool, Integer, String or any enumeration type. Furthermore, any conditional or optional types can be used, and then a "Nil" variant will be available. This can be very useful for forking the program execution on the basis on whether some analysis was successful (there exists a proper value) or not (Nil).

All variants share a single external interface – inputs, outputs and also registers are the same. In consecutive iterations different variants might be executed, but they can exchange information internally through the local registers of this macrofilter. From outside a variant step looks like any other filter.

Here are some example applications of variant macrofilters:

• When some part of the program being created can have multiple alternative implementations, which we want to be chosen by the end-user. For example, there might be two different methods of detecting an object, having different trade-offs. The user might be able to choose one of the methods through a combo-box in the HMI or by changing a value in a configuration file.
• When there is an object detection step which can produce several classes of detected objects, and the next step of object recognition should depend on the detected class.
• When an inspection algorithm can have multiple results (most typically: OK and NOK) and we want to executed different communication or visualization filters for each of the cases.
• Finite State Machines.

Variant Step macrofilters correspond to the switch statement in C++.

### Example 1

A Variant Step can be used to create a subprogram encapsulating image acquisition that will have two options controlled with a String-typed input:

2. Variant "Camera": Grabbing images from a camera.

The two variants of the GrabImageOrLoad macrofilter.

In the Project Explorer, the variants will be accessible after expanding the macrofilter item:

A variant step macrofilter in the Project Explorer

### Example 2

Another application of Variant Step macrofilters is in creating optional data processing steps. For example, there may be a configurable image smoothing filter in the program and the user may be able to switch it on or off through a CheckBox in the HMI. For that we create a macrofilter like this:

A variant step macrofilter for optional image preprocessing.

NOTE: Using a variant step here is also important due to performance reasons. Even if we set inStdDev to 0, the SmoothImage_Gauss filter will still need to copy data from input to output. Also filters such as ChooseByPredicate or MergeDefault perform a full copy. On the other hand, when we use macrofilters, internal connections from macrofilter inputs to macrofilter outputs do not copy data (but they link them). If this is about heavy types of data such as images, the performance benefit can be significant.

A Task macrofilter is much more than a separated sequence of filters. It is a logical program unit realizing a complete computing process. It can be used as a subprogram, but when it has not inputs and outputs, it can be considered a complete program by itself. What is important to note, however, in majority of typical machine vision systems there is only one Task – the "Main" macrofilter. Additional tasks are required in more advanced situations, for example:

• When we need an explicit nested loop in the program which cannot be easily achieved with array connections.
• When we need to perform some computations before the main program loop starts.
• When we want to have additional programs in a project for unit testing of our algorithms.
• When we want to have additional programs in a project for precomputing some data that will be used in the main program.

### Execution Process

The most important difference between Tasks and Steps is that a Task can perform many iterations of its filter sequence before it finishes its own single invocation. This filter sequence gets executed repeatedly until one of the contained loop generating filters signals an end-of-sequence. If there are no loop generators at all, the task will execute exactly one iteration. Then, when the program execution exits the task (returning to the parent macrofilter) the state of the task's filters and registers is destroyed (which includes closing connections with related I/O devices).

What is also very important, Tasks define the notion of an iteration of the program. During program execution there is always a single task that is the most nested and currently being executed. We call it the current task. When the execution process comes to the end of this task, we say that an iteration of a program has finished. When the user clicks the Iterate (F6) button, execution continues to the end of the current task. Also the Update Data Previews Once an Iteration refers to the same notion.

Task macrofilters can be considered an equivalent of C/C++ functions with a single while loop.

### Example: Initial Computations before the Main Loop

A quite common case, when we need to use a task macrofilter, is when some filters have to be executed before the main loop of the program starts. Typical examples of such initial computations are: setting some camera parameters, establishing some I/O communication or loading some model definitions for external files. Programs of this kind should have the following standard structure consisting of two parts:

The standard program structure with separated initialization (step or task) and main loop (task).

When the program is started, the "Initialize" macrofilter will be executed once and then the loop of the "MainLoop" task will be executed until the program ends.

## Ports of Macrofilters

### Inputs

Macrofilter inputs are set before execution of the macrofilter is started. In the case of Task macrofilters the inputs do not change values in consecutive iterations.

### Outputs

Macrofilter outputs can be set from connections with filters or with global parameters as well as from constant values defined directly in the outputs.

In the case of Tasks (with many iterations) the value of a connected output is equal to the value that was computed the latest. One special case to be considered is when there is a loop generator that exits in the very first iteration. As there is no "the latest" value in this case, the output's default value is used instead. This default value is part of the output's definition. Furthermore, if there is a conditional connection at an output, Nil values cause the previously computed value to be preserved.

### Registers

Registers make it possible to pass information between consecutive iterations of a Task. They can also be defined locally in Steps and in Variant Steps, but their values will still be set exactly in the same way as if they belonged to the parent Task:

• Register values are initialized to their defaults when the Task starts.
• Register values are changed at the end of each iteration.

In case the of variant macrofilters, register values for the next iteration are defined separately in each variant. Very often some registers should just preserve their values in most of the variants. This can be done by creating long connections between the prev and next ports, but usually a more convenient way is to disable the next port in some variants.

Please note, that in many cases it is possible to use accumulating filters (e.g. AccumulateElements, AddIntegers_OfLoop and other OfLoop) instead of registers. Each of these filters has an internal state that stores information between consecutive invocations and does not require explicit connections for that. Thus, as a method this is simpler and more readable, it should be preferred. Registers, however, are more general.

Yet another alternative to macrofilter registers is the prev operator in the formula blocks.

Registers correspond to variables in C/C++. In Adaptive Vision Studio, however, registers follow the single assignment rule, which is typical for functional and data-flow programming languages. It says that a variable can be assigned at most once in each iteration. Programs created this way are much easier to understand and analyze.

### Example: Computing Greatest Common Denominator

With Task macrofilters and registers it is possible to create very complex algorithms. For example, here is a comparison of how the Greatest Common Denominator function can be implemented in Adaptive Vision Studio and in C/C++:

 A task with registers computing Greatest Common Denominator of inA and inB. int gcd(int inA, int inB) { int a = inA; int b = inB; while (a != 0) { int tmp = a; a = b % a; b = tmp; } return b; }  Computing Greatest Common Denominator in C++.

## Sequence of Filter Execution

It can be assumed that filters are always executed from top to bottom. Internally the order of filter execution can be changed and even some filters may operate in parallel to take advantage of multi-core processors, but this happens only if the top-down execution produces exactly the same results. Specifically, all I/O functions will never be parallelized, so if one I/O operation is above another, it will always be executed first.

 Previous: Generic Filters Next: Formulas