# LumiScan Template Finder 1.1.0.7 – complete documentation

> All pages of the LumiScan Template Finder 1.1.0.7 manual (language: en) by HD Vision Systems GmbH, in navigation order. Each page starts with a level-1 heading followed by its URL; cite that URL. Manual: https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/

# Description – LumiScan Template Finder

URL: https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/description.html

LumiScan Template Finder locates a known part inside a camera image. You give it a small picture of the part - the **template** - and it reports where that part appears in a larger image, how confident the match is, and at what scale and rotation it was found.

Typical uses are presence checks, position feedback for a robot pick, and orientation checks before an assembly step.

The application runs on ctrlX OS (ctrlX CORE or ctrlX IPC), where it uses the ctrlX Data Layer, and on a PC with Windows 11 or Ubuntu 24.04, where it uses LumiScan Keryx. Its nodes, and how they are called, are the same on both. See [Data Layer Reference](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/datalayer-reference.html).

What is the same for every LumiScan app - how addresses are built, the handshake, execute and stream call patterns, status codes, settings and tools - is described in the [LumiScan Keryx](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/index.html) manual. This manual covers only what is specific to LumiScan Template Finder; its own nodes are listed in the [Data Layer Reference](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/datalayer-reference.html).

## What the application does

The application provides two operations.

**Creating a template** cuts a rectangular region out of a live camera image and saves it as a PNG in the application’s configuration directory. This is how you produce a template from the real camera, in the real lighting, at the real working distance - no file transfer and no image editor needed. See [Creating a Template](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/creating-a-template.html).

**Finding a template** searches a live camera image for that template and reports every occurrence it finds. See [Finding a Template](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/finding-a-template.html).

Both operations read the image from another application’s Data Layer image node - normally LumiScan Cam Driver - at the moment they are called, so they always work on the current image. A module can also search every frame a camera streams, see [Finding Templates on an Image Stream (Experimental)](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html).

## Where the images come from

The application does not talk to a camera itself. It is given the **address** of an image node published by another application:

```
hdvisionsystems/lumiscan-cam-driver/camera1/output/image
```

That keeps the two concerns apart: the camera application owns triggering and exposure, this application owns matching. It also means the same image can be used by several applications at once, and that you can point the template finder at a different camera by changing one string.

## Modules

A configuration of the application is a **module**, with its own template, its own search parameters and its own results, under its own address:

```
hdvisionsystems/lumiscan-template-finder/module-1/
```

A fresh installation serves one module, `module-1`, and further modules can be created while the application runs, so one installation can serve several camera configurations at once.

> [!IMPORTANT]
> **On ctrlX OS, one licence covers ten modules.** The eleventh acquires a second licence of the same key.

Modules are independent, except that they share one template directory - so a template created by one module can be used by all of them. Their settings, and the module list itself, can be saved so they return after a restart. See [Module Management](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/module-management.html).

## What a result contains

A successful search reports, for every occurrence found:

- the **oriented bounding box** - centre, width, height and angle in the image
- the **confidence**, between 0 and 1
- the **scale** and **rotation** the match was found at

Results are sorted by confidence, so the best match is always the first entry. Every operation also reports a numeric status code and a status message, which is how a PLC checks whether the run succeeded - see [Execution Status](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/execution-status.html).

# Requirements – LumiScan Template Finder

URL: https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/requirements.html

## Licence {#licence}

How LumiScan Template Finder is licensed depends on where you bought it and where it runs:

| Bought from | Runs on | Licensing |
| --- | --- | --- |
| HD Vision Systems | Windows 11 or Ubuntu 24.04 | The licence is held on your LumiScan Key. It is a one-time purchase and needs no renewal.<br><br>[Licensing path: bought from HD Vision Systems](https://docs.hdvisionsystems.com/en/lumiscan-licensing/1.0.4/path-hdvs.html) |
| ctrlX Store | Windows 11 | The licence is held in ctrlX WORKS. The LumiScan Key is required in addition; it protects the software against reverse engineering.<br><br>[Licensing path: ctrlX Store, Windows](https://docs.hdvisionsystems.com/en/lumiscan-licensing/1.0.4/path-ctrlx-windows.html) |
| ctrlX Store | ctrlX OS (ctrlX CORE or IPC) | ctrlX licence `SWL-W-XCx-TEMPLxFDxxHDVS-V1NN`, one licence per ten modules.<br><br>[Licensing path: ctrlX Store, ctrlX OS](https://docs.hdvisionsystems.com/en/lumiscan-licensing/1.0.4/path-ctrlx-os.html) |

Each device on which LumiScan Template Finder runs at the same time needs its own LumiScan Key. Keys can be exchanged between devices.

How to install CodeMeter Runtime and how to request, renew and move licences is described in [LumiScan Licensing](https://docs.hdvisionsystems.com/en/lumiscan-licensing/1.0.4/index.html).

On ctrlX OS, the application shuts down shortly after starting if the licence is missing; the reason is written to the system log.

## A platform and its Data Layer

| Platform | Data Layer |
| --- | --- |
| ctrlX OS (ctrlX CORE or ctrlX IPC) | ctrlX Data Layer, provided by ctrlX OS |
| a PC with Windows 11 or Ubuntu 24.04 | LumiScan Keryx, the Data Layer of HD Vision Systems for PCs |

On ctrlX OS there is nothing to install for the Data Layer.

On a PC the application starts the LumiScan Keryx broker when none is running; installing and setting up LumiScan Keryx is described in [LumiScan Keryx on a PC](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/keryx.html).

## An image source on the same device

The application reads its images from another application’s Data Layer image node. That application must run on the **same device** - the same ctrlX CORE or ctrlX IPC, or the same PC. Remote Data Layer access is not supported.

In practice this is LumiScan Cam Driver, but any application works as long as its image node provides these four children:

| Node | Type | Description |
| --- | --- | --- |
| `data` | array of uint8 | Raw, uncompressed pixel data |
| `width` | uint64 | Image width in pixels |
| `height` | uint64 | Image height in pixels |
| `pixel-type` | string | GenICam pixel format name |

### Supported pixel formats

`Mono8`, `Mono12`, `RGB8`, `RGB12`, `BGR8`, `BGR12`, `BayerGR8`, `BayerGR12`, `BayerRG8`, `BayerRG12`.

Bayer images are converted to colour and 12-bit images are scaled down to 8 bit before matching, so templates cut from one format still match images of another.

Any other pixel format is rejected with status code `-3`.

## Storage

Templates are stored as PNG files in the application’s configuration directory. On ctrlX OS this directory is part of the active solution. Allow for the size of the templates you expect to keep - a template is a small crop, typically a few tens of kilobytes.

The directory is created on first start. See [Template Storage](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/template-storage.html).

The image stream (experimental) adds one folder beside them, `settings-history/`: one small JSON file for each settings hash a module publishes, never deleted. See [Finding Templates on an Image Stream (Experimental)](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html).

## Timing

Matching is **synchronous**: the call to `execute` returns when the search has finished. How long that takes depends on the image size, the template size, and above all on how wide a scale and rotation range is searched - the work is one pass per scale/rotation combination.

Start from the defaults, which search a single scale and rotation, and widen only as far as the application actually needs. See [Tuning the Search](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/tuning-the-search.html).

# How To: Match a Part from a Camera Image – LumiScan Template Finder

URL: https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/how-tos/match-a-part-from-a-camera-image.html

End-to-end walkthrough, from a running camera to a match result, using the module the application creates for you on installation.

## Before you start

- LumiScan Cam Driver, or another image source, is running on the same device - the same ctrlX CORE or ctrlX IPC, or the same PC - and has captured an image.
- You know the address of its image node. For camera 1 of the cam driver:
  ```
  hdvisionsystems/lumiscan-cam-driver/camera1/output/image
  ```

Throughout, paths are relative to the application:

```
hdvisionsystems/lumiscan-template-finder/
```

Creating a template is an operation of the whole application, under `system/`; the search belongs to the module `module-1`.

## Step 1 - Point both operations at the camera

Set the image address on both operations:

```
system/create-template/input/input-image-address = hdvisionsystems/lumiscan-cam-driver/camera1/output/image
module-1/find-template/input/input-image-address = hdvisionsystems/lumiscan-cam-driver/camera1/output/image
```

They are separate nodes on purpose - a template can be cut from one camera and searched for in another.

## Step 2 - Capture an image with the part in view

Trigger a capture in the camera application, with the part positioned as it will be in production. The template is cut from this image, so its lighting and working distance become the reference.

## Step 3 - Cut the template

Find the pixel coordinates of a region containing the part. The camera application’s image preview is the easiest way to read them off.

Then:

```
system/create-template/input/crop/startX    = 100
system/create-template/input/crop/startY    = 200
system/create-template/input/crop/width     = 190
system/create-template/input/crop/height    = 100
system/create-template/input/template-name = screw
```

Write to `system/create-template/execute`, then read `system/create-template/output/status-code`.

`1` means it worked, and `system/create-template/output/template-path` now reads `templates/screw.png`.

If you get `-5`, the region does not fit the image; `output/status-text` names the actual image size.

## Step 4 - Verify against the same image

Before changing anything, search the image you just cut from:

```
module-1/find-template/input/template-name = screw
```

Write to `module-1/find-template/execute` and read `module-1/find-template/output/result`.

You should get exactly one match, its `oriented_bounding_box` centred at the middle of the region you specified - (195, 250) for the values above - with a confidence close to 1.

> [!TIP]
> This check is worth the half minute it takes. If the template is not found in the very image it came from, the problem is the region or the image address, and no amount of parameter tuning will fix it.

## Step 5 - Search a real image

Capture a new image with the part in a different position and search again. The match should follow the part.

If nothing is found, the part has probably changed size or orientation relative to the template. Go to step 6.

## Step 6 - Widen the search, if needed

Only if step 5 failed:

**The part rotates.** Set a rotation range with a coarse step:

```
module-1/find-template/input/rotation/max-rot  = 360
module-1/find-template/input/rotation/step-rot = 5
```

**The part changes distance.** Set a scale range:

```
module-1/find-template/input/scale/min-scale  = 0.9
module-1/find-template/input/scale/max-scale  = 1.1
module-1/find-template/input/scale/step-scale = 0.05
```

Each combination is a separate pass over the image, so both settings together are 72 x 5 = 360 passes. Widen one at a time and stop as soon as the part is found reliably.

If widening the range starts producing matches in the wrong places, raise the threshold:

```
module-1/find-template/input/match-thresh = 0.95
```

The reason is explained in [Tuning the Search](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/tuning-the-search.html).

## Step 7 - Keep the settings

The settings are live but not yet permanent. To have them restored after a restart:

```
system/save-module-inputs/input/module-id = module-1
```

Write to `system/save-module-inputs/execute`.

The template file itself is already permanent - it is a file in the application’s configuration directory, which on ctrlX OS is part of the active solution.

## In production

A cycle is now a single write to `module-1/find-template/execute`, followed by:

1. read `module-1/find-template/output/status-code` - negative means the search failed
2. read `module-1/find-template/output/result` - `best_score` and `matches[0]` give the best match

Nothing else needs to be set between cycles. To have every frame of the camera searched without a call per image, see [Finding Templates on an Image Stream (Experimental)](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html).

# How To: Get Reliable Results with the Right Template and Scene – LumiScan Template Finder

URL: https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/how-tos/get-reliable-results.html

LumiScan Template Finder finds a part by comparing a template, a small image of the part, with the camera image. How well this works depends less on the search parameters than on the template and the scene: a template that matches the scene is found reliably with the default settings; a template that does not match cannot be rescued by tuning.

This page explains what to look out for and shows three examples. The procedure itself - cutting a template and searching for it - is described in [How To: Match a Part from a Camera Image](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/how-tos/match-a-part-from-a-camera-image.html).

## What makes the search reliable {#rules}

- **Take the template from the same setup:** Cut the template from an image of the camera that will search for it, with the part where it will be in production. Lighting, working distance and background are then the same in the template and in the image. LumiScan Template Finder cuts the template directly from the live camera image for this reason, see [Creating a Template](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/creating-a-template.html).
- **Keep the part the same size in pixels:** The part must appear at about the same size in the template and in the searched image. A template from another camera, another lens or another working distance has a different scale. If the distance varies in production, set a scale range, see [Tuning the Search](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/tuning-the-search.html#_search_range).
- **Keep the lighting constant:** Shadows, reflections and changes in brightness change the appearance of the part and lower the score. Use a dedicated illumination and shield the station from daylight and changing ambient light.
- **Keep the background consistent and calm:** The template contains some of the background around the part. If the background in production differs from that in the template, every score drops. A matt, non-reflective background in an even colour works best; it also keeps reflections off the part.
- **Include what identifies the part, exclude what varies:** Cut the template tightly around distinctive features. Background that changes from part to part, or parts of neighbouring objects, belong outside the region.

## Examples {#examples}

The three examples search ring-shaped parts. Each found part is framed and labelled with its score; the part the template was cut from scores `1.00`.

### Example 1 - Template from the same scene, light grey background {#example-1}

|   |   |   |
| --- | --- | --- |
| ![Six metal rings on a light grey background](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/_images/howto-reliable-grey-scene.png)<br><br>*Figure 1. Search image* | ![Template: one ring cut from the search image](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/_images/howto-reliable-grey-template.png)<br><br>*Figure 2. Template* | ![Five rings framed with scores between 0.82 and 1.00; of the two touching rings at the bottom](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/_images/howto-reliable-grey-result.png)<br><br>*Figure 3. Result* |

Five of the six rings are found, at the right positions. Of the two rings that touch at the bottom, only one is found, and it is reported twice. Parts that touch each other are harder to separate than parts that lie apart. The ring on the right, seen at a slight angle, scores lower (`0.87`) because it looks different from the template.

### Example 2 - Template from the same scene, textured blue background {#example-2}

|   |   |   |
| --- | --- | --- |
| ![Six metal rings on a textured blue cloth](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/_images/howto-reliable-blue-scene.png)<br><br>*Figure 4. Search image* | ![Template: one ring cut from the search image](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/_images/howto-reliable-blue-template.png)<br><br>*Figure 5. Template* | ![All six rings framed](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/_images/howto-reliable-blue-result.png)<br><br>*Figure 6. Result* |

All six rings are found. The rings lie apart, so each frame contains only one ring and background. The scores vary with the reflections on the individual rings, from `0.72` to `1.00`.

### Example 3 - Template from another scene {#example-3}

The template from example 2, cut on the blue background, is used to search the light grey image of example 1.

|   |   |   |
| --- | --- | --- |
| ![Six metal rings on a light grey background](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/_images/howto-reliable-grey-scene.png)<br><br>*Figure 7. Search image* | ![Template: a ring on blue background](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/_images/howto-reliable-blue-template.png)<br><br>*Figure 8. Template* | ![Four frames](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/_images/howto-reliable-mixed-result.png)<br><br>*Figure 9. Result* |

The result is unusable: two rings are not found, and the frames are too large and shifted against the rings. The template differs from the scene in background, in lighting, and in size - the ring is larger in pixels than the rings in the search image. The best match of a search always scores close to `1.00`, so a high score alone does not prove a correct position, see [Understanding the confidence](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/tuning-the-search.html#_understanding_the_confidence).

The remedy is not a parameter but a new template, cut from the grey scene.

## Checklist {#checklist}

1. The template is cut from the camera that searches, in the production setup.
2. The part has about the same size in pixels in the template and in the image. Otherwise, a scale range is set.
3. The lighting is the same when the template is cut and in production.
4. The background is the same, matt and even.
5. The template is found in the image it was cut from, at the centre of the region, with a score near `1`.

If the part is still not found, or found in the wrong places, see [Troubleshooting](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html).

# Execute a Method – LumiScan Template Finder

URL: https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/execute-a-method.html

Every operation of this application - matching, template creation and module management - is started the same way, and reports its outcome the same way.

## The shape of an operation

An operation lives under its own address and always has three parts:

```
<operation>/execute                 write here to run it
<operation>/input/...               the values it works on
<operation>/output/status-code      what happened, as a number
<operation>/output/status-text      what happened, in words
```

Some operations have more under `output/` - a match result, or the path of a written file - but `execute`, `status-code` and `status-text` are always there.

## Running an operation

1. Write the input nodes.
2. Write to `execute`. The value does not matter; the write itself triggers the operation.
3. Read `output/status-code` to find out whether it worked.

Writing to `execute` is a **blocking call**: it returns when the operation has finished, so there is no need to poll a "ready" flag or track state in your program. Inputs keep their values between runs, so a repeated operation only needs step 2.

## Checking the outcome

`output/status-code` is a signed number, and **the sign alone tells you whether it worked**:

| Value | Meaning |
| --- | --- |
| greater than 0 | The operation succeeded |
| 0 | The operation has not run since the application started |
| less than 0 | The operation failed and produced nothing |

So the check in a PLC is simply `status-code < 0`. You only need a specific code when you want to react differently to different failures - a missing template, say, versus a camera that is not answering.

`output/status-text` carries the same outcome as a sentence, and names the offending value when there is one:

```
ok: 3 match(es) using 'screw.png'
error: crop/startX + crop/width (100 + 900 = 1000) exceeds the image width 640
```

Read it when something goes wrong; do not build logic on it, because the wording can change between releases. The full list of codes is in [Execution Status](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/execution-status.html).

> [!NOTE]
> The reason arrives on `output/status-text`, not in the response to the `execute` write itself. A failed write answers with a status code only - over REST, a bare `400`. The Data Layer discards any detail a provider attaches to a failed call, so reading `output/status-text` afterwards is the way to find out what was wrong. The result codes of a write on both Data Layers are listed in [Results of a method call](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/status-codes.html#method-results).
>
> The same text is written to the application log, so a failure is also diagnosable without touching the Data Layer at all: on ctrlX OS in the ctrlX Logbook or with `journalctl`, on a PC in the application’s console output. When several inputs are wrong, each one gets its own warning line.

## One operation at a time

A module runs one operation at a time. Starting a second one while the first is still running does not queue it - it returns immediately with status code `-1` (busy) and does nothing. The write itself answers `TooManyOperations` (ctrlX: `DL_TOO_MANY_OPERATIONS`), see [One operation at a time](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/execute.html#busy).

The lock is per module, so different modules match in parallel - a second camera is not held up by the first. `system/create-template` has its own lock, so creating a template does not block matching and two creations cannot race.

## The outputs belong to the run that is starting

Every method clears its own output nodes as soon as it begins - `find-template` its `output/result`, `create-template` its `output/template-path`. They are cleared **before** anything that can fail, so a run that fails for any reason leaves them empty rather than holding what an earlier run produced.

That is what makes it safe to read an output without checking `output/status-code` first: what you see is either this run’s work or nothing, never a stale value from a previous image.

`output/status-code` and `output/status-text` are the exception - they always describe the latest attempt, which is the whole point of them.

> [!WARNING]
> **Read an output before triggering the next run.** The outputs describe the most recent run, and the next call empties them the moment it starts. Calling `execute` again and then reading the previous result gives you nothing.
>
> The one case that does **not** clear anything is a call rejected as `-1` (busy): it never ran, so it leaves the running operation’s outputs alone. So a second `execute` fired immediately after the first has two possible outcomes, and they differ:
>
> - the first run is **still going** - the second is refused with `-1`, and the outputs still hold the run before it;
> - the first run has **just finished** - the second is accepted, and it clears the outputs the first run had only just written.
>
> Wait for `execute` to return, read the outputs, and only then trigger the next run.

# Execution Status – LumiScan Template Finder

URL: https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/execution-status.html

Every operation reports its outcome on two nodes beside it: `output/status-code` for your program, and `output/status-text` for a person.

## Status codes

| Code | Meaning | When it happens |
| --- | --- | --- |
| `0` | Idle | The operation has not run since the application started |
| `1` | OK | The operation completed. A search may still have found nothing - that is a normal result, not an error |
| `-1` | Busy | Another operation of the same module was still running. Nothing was done; try again when it has finished |
| `-2` | Invalid input | An input value cannot be used - a required node left empty, an unknown match mode, an image address pointing at this application itself, or a directory path that is absolute or points outside the configuration directory |
| `-3` | Image read failed | The image node at the given address is missing, empty, inconsistent, or uses an unsupported pixel format. Check that the camera application is running and has captured an image |
| `-4` | Source not found | The template directory or the template file is missing or unreadable. Check the name against `system/templates`, and check `system/template-dir`: all modules share one template directory |
| `-5` | Invalid crop region | The region of interest does not fit inside the image. The message names the actual image size |
| `-6` | Write failed | A file could not be written - usually a permission problem or a full disk |
| `-7` | Algorithm failed | The matching itself failed |
| `-8` | Publish failed | The result could not be written back to the Data Layer |
| `-9` | Module not found | The named module does not exist. Check `system/modules` for the current list |
| `-10` | Module already exists | A module with that name is already there |
| `-11` | Licence unavailable | No licence covers the module. See [Module Management](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/module-management.html) |

These codes are the finders' own execution status, not the module status codes of the Cam Driver or AI Object Matching: `-5` here means an invalid crop region. See [Execution status of the finders](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/status-codes.html#execution-status).

> [!NOTE]
> These numbers are part of the application’s interface. New codes may be added in later releases, but existing ones never change meaning, so logic written against them keeps working after an update.
>
> This is also why checking the **sign** is the more robust test: `status-code < 0` stays correct even when a release introduces a failure your program has never seen.

## Which operation reports which

| Operation | Possible codes |
| --- | --- |
| Finding a template | `1`, `-1`, `-2`, `-3`, `-4`, `-7`, `-8` |
| Creating a template | `1`, `-1`, `-2`, `-3`, `-5`, `-6` |
| `system/save-module-inputs` | `1`, `-6`, `-9` |

## Status text

`output/status-text` always starts with `ok:` or `error:` and gives the reason in words. It is written at the same time as the status code, so both always agree.

Each operation has its own pair of nodes, and they keep their values until that operation runs again. A failed template creation therefore does not disturb the result of the last search.

# Creating a Template – LumiScan Template Finder

URL: https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/creating-a-template.html

A template is a small picture of the part you want to find. This operation cuts one out of a live camera image and saves it, so the template comes from the real camera in the real lighting.

The operation belongs to the whole application, not to a module, so it sits on the system node:

```
hdvisionsystems/lumiscan-template-finder/system/create-template/
```

## Inputs

| Node | Type | Default | Description |
| --- | --- | --- | --- |
| `input/input-image-address` | string | *(empty)* | Data Layer address of the image to cut from. Required |
| `input/crop/startX` | int32 | `0` | Left edge of the region, in pixels from the left of the image |
| `input/crop/startY` | int32 | `0` | Top edge of the region, in pixels from the top of the image |
| `input/crop/width` | int32 | `0` | Width of the region in pixels. Must be greater than 0 |
| `input/crop/height` | int32 | `0` | Height of the region in pixels. Must be greater than 0 |
| `input/template-name` | string | *(empty)* | Name to save under. `.png` is added if you give no extension. Use a lower case name: only lower case `.png` files appear on `system/templates`. Required |

The template is written into `system/template-dir`, which the whole application shares, so it is usable by every module as soon as it is saved.

## Outputs

| Node | Type | Description |
| --- | --- | --- |
| `output/template-path` | string | Path of the written file, relative to the configuration directory |
| `output/status-code` | int16 | Execution status |
| `output/status-text` | string | The same outcome in words |

`output/template-path` is split the way the search expects it: `templates/screw.png` means set the search’s template directory to `templates` and its template name to `screw.png`.

## Procedure

1. Make sure the camera application has captured an image.
2. Set `input/input-image-address`.
3. Set the four `input/crop/` values to the region containing the part.
4. Set `input/template-name`.
5. Write to `system/create-template/execute`.
6. Read `output/status-code`. On `1`, `output/template-path` names the new template.

> [!TIP]
> Immediately search the **same image** for the template you just cut. It must be found at exactly the centre of the region you specified, with a confidence near 1. If it is not, the problem is the region or the image source - not the search parameters. This takes a few seconds and saves a lot of guessing later.

## Choosing a good region

- **Include what identifies the part, exclude what varies:** Background that changes from part to part lowers every score.
- **Keep it small, but distinctive:** Matching cost grows with template area. A small, high-contrast feature is both faster and more reliable than the whole part.
- **Stay away from the image border:** A template that touches the edge of the image cannot be found near the opposite edge, because the template must fit entirely inside the searched image.
- **Think about binning:** If the search will run with binning, the template must still be recognisable after downsampling. At a bin size of 4, a feature 20 pixels wide becomes 5.

## Written file

The region is written as a standard 8-bit RGB PNG, whatever the camera’s pixel format - Bayer images are converted to colour and 12-bit images scaled down first.

The destination directory is created if it does not exist.

> [!WARNING]
> An existing file with the same name is overwritten without warning. Use a new template name if you want to keep the old one.

# Finding a Template – LumiScan Template Finder

URL: https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/finding-a-template.html

Searches a live camera image for a stored template and reports every occurrence found.

Address, relative to the module:

```
find-template/
```

## Inputs

The two required values are the image to search and the template to look for. Everything else has a working default; the parameters that control the search itself are described in [Tuning the Search](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/tuning-the-search.html).

| Node | Type | Default | Description |
| --- | --- | --- | --- |
| `input/input-image-address` | string | *(empty)* | Data Layer address of the image to search. Required |
| `input/template-name` | string | *(empty)* | Template to search for, as listed on `system/templates`. `.png` is added if you give no extension. Required |

The directory it is read from is `system/template-dir`, which the whole application shares - see [Template Storage](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/template-storage.html).

## Outputs

| Node | Type | Description |
| --- | --- | --- |
| `output/result` | flatbuffer | The matches found, sorted by confidence |
| `output/status-code` | int16 | Execution status |
| `output/status-text` | string | The same outcome in words |

## The result

`output/result` is a `hdv.template_match.Result` flatbuffer:

| Field | Type | Description |
| --- | --- | --- |
| `matches` | array | One entry per occurrence found, sorted by confidence, highest first |
| `best_index` | ulong | Index of the best match. Always `0`, because the list is sorted |
| `best_score` | float | Confidence of the best match, or `0.0` if nothing was found |
| `template_name` | string | The template used for this run |
| `match_mode` | string | The matching algorithm used |
| `match_thresh` | float | The threshold applied |
| `image_width`, `image_height` | uint | Size of the searched image, so coordinates can be normalised |
| `timestamp` | ulong | Microseconds since the epoch, taken when the search finished |

Each entry in `matches` contains:

| Field | Type | Description |
| --- | --- | --- |
| `oriented_bounding_box` | struct | `center_x`, `center_y`, `width`, `height` in pixels, and `angle` in **degrees** |
| `confidence` | float | Match score between 0 and 1 |
| `scale` | float | The template scaling factor this match was found at |
| `rotation` | float | The template rotation this match was found at, in degrees |

> [!NOTE]
> An empty `matches` list together with status code `1` means the search ran correctly and found nothing. That is a normal result - the part is simply not there, or not similar enough to pass the threshold. It is not an error.

## Procedure

1. Set `input/input-image-address` and `input/template-name`.
2. Adjust the search parameters if the defaults do not fit - see [Tuning the Search](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/tuning-the-search.html).
3. Write to `find-template/execute`.
4. Read `output/status-code`. `1` means the search ran.
5. Read `output/result` for the matches, or `output/status-text` if the status code was negative.

Once the inputs are set they keep their values, so a repeated search is a single write to `execute`.

## Common failures

Failures are described step by step in [Troubleshooting](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html):

- [Status code `-2` (invalid input)](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#faq-status-minus-2)
- [Status code `-3` (image read failed)](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#faq-status-minus-3)
- [Status code `-4` (source not found)](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#faq-status-minus-4)
- [The result is empty although the status code is `1`](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#ts-empty-result)

## Searching only part of the image

`input/crop/` limits the search to a rectangle - faster, and it avoids matching a part that happens to appear elsewhere in the frame. All four values are `uint16`.

A **zero width or height means "as far as the image goes"** on that axis:

| Setting | Region searched |
| --- | --- |
| all four zero (the default) | the whole image |
| `startX=100, startY=50`, sizes zero | from (100, 50) to the bottom-right corner |
| `width=0, height=200` | a 200 pixel band reaching the right edge |

A region reaching past an edge is **refused, not trimmed** - searching a smaller area than asked for would show up much later as matches that are simply missing. The reason names the input and the limit it broke, for example `crop/startX + crop/width (100 + 541 = 641) exceeds the image width 640`. A region smaller than the template is refused too, with status `-5`.

## Which image the positions refer to

`input/result-coordinate` decides what the positions in `output/result` are measured against:

| Value | Meaning |
| --- | --- |
| `IMAGE` (default) | The full image at `input-image-address`, so a position can be used directly for a robot pick whatever the crop region is |
| `CROP` | The searched region, whose top left corner is (0,0) |

It changes only how the result is reported, never what is found. `image_width` and `image_height` in the result follow the same choice.

## What a failed search leaves behind

The matches are cleared before the search starts, so a run that fails for any reason leaves `output/result` empty rather than holding the hits from an earlier image. Reading the result without checking `output/status-code` therefore shows nothing, not a stale match.

Status `-1` (busy) is the exception: that call never ran, so it leaves the result of the search that is in progress alone.

## Searching every frame of a camera

`find-template` searches one image per call. To have a module search every frame a camera streams, with the same inputs, see [Finding Templates on an Image Stream (Experimental)](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html).

# Finding Templates on an Image Stream (Experimental) – LumiScan Template Finder

URL: https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html

> [!IMPORTANT]
> The image stream is **experimental**. Its nodes and settings may still change. Use it for evaluation, and verify it with your cameras and your Data Layer before relying on it.

`find-template` searches one image per call: your program sets `input/input-image-address` and writes to `execute`. An image stream works the other way round. The Cam Driver publishes every image it takes on `<camera name>/control/publish/output/stream/frame`, with its size, its pixel format and its lineage (see the Cam Driver manual, *Streaming Images*). A module subscribes to the stream of one camera, searches each frame as it arrives, and publishes one result per frame on `control/subscribe/output/stream/result`.

Each frame is searched with the inputs of `find-template` as they are at that moment: the template, the crop region, the scale and rotation ranges and every other node under `find-template/input/`. The one input the stream does not use is `input/input-image-address`: the frame takes its place. If you change an input while the stream runs, the next frame is searched with the new value.

Each result carries the lineage of its frame - which camera took it, in which run of the camera’s stream, as which frame of the run - with the module’s own step added. See [The lineage of a result](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html#lineage).

By default the module never falls behind its camera. When frames arrive faster than the module searches them, it takes the newest frame each time the previous search is finished. The frames in between are counted as skipped. How many frames may wait is set with the queue size, see [The queue size](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html#queue-size).

A module takes the stream of one camera. For another camera, or other settings, use another module.

The stream nodes, and how a stream is started and stopped, are the same in every LumiScan app that consumes a stream; [Streams (Experimental)](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/streams.html) in the Data Layer manual describes them in general. This page describes what is particular to the Template Finder.

## The stream’s nodes {#addresses}

Every module has the stream’s nodes, whether it subscribes to a stream or not. No restart is needed to start using them. All addresses below start with `hdvisionsystems/lumiscan-template-finder/<module-id>/`. They sit beside `find-template/`, not inside it.

**Table 1. Methods**

| Address | Meaning |
| --- | --- |
| `control/subscribe/execute` | Checks the five inputs of `control/subscribe` together, saves them in the module’s settings file, then applies them: a running stream follows on its next cycle, with no restart. Writing an input alone changes nothing. See [Changing the source](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html#subscribing). |
| `control/unsubscribe/execute` | Drops the source named by `control/unsubscribe/input/address`, which ends stream mode too. The tag stays. Saved in the module’s settings file like a subscribe. |

**Table 2. Inputs of control/subscribe**

| Address | Type | Meaning |
| --- | --- | --- |
| `control/subscribe/input/enable` | bool | Stream mode: `true` runs the stream, `false` stops it. |
| `control/subscribe/input/address` | string | The one source: a camera’s stream folder, for example `hdvisionsystems/lumiscan-cam-driver/camera1/control/publish/output/stream`. The module reads its `frame` node. Another address replaces the source. |
| `control/subscribe/input/tag` | string | The tag the module puts on its results: the module’s step in the lineage of each result carries it, so whoever reads a result downstream sees which module made it. Empty: the module id, the last segment of the module’s address, for example `module-1`. A new tag marks the next result; the source stays subscribed. |
| `control/subscribe/input/queue-size` | uint32 | How many frames may wait while a frame is searched: `1` to `64`. See [The queue size](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html#queue-size). |
| `control/subscribe/input/keep-latest-output` | bool | `true` to write each stream result to `find-template/output/result` as well. See [Keeping the latest output](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html#keep-latest-output). |

The inputs start with what is applied at the start of the application, so a client can change one of them and execute.

What the source must hold: read `hdvisionsystems/lumiscan-template-finder/system/meta/subscription-schema`, the same for every module. It is a JSON Schema of the `frame` node of the source, a `stream_image` with its `lineage` and its `image`, in its JSON form. See [Data Layer Reference](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/datalayer-reference.html).

**Table 3. Input of control/unsubscribe**

| Address | Type | Meaning |
| --- | --- | --- |
| `control/unsubscribe/input/address` | string | The source to drop: the address `setting/stream/address` shows. A `/` at either end does not count. |

**Table 4. Settings**

| Address | Type | Meaning |
| --- | --- | --- |
| `setting/stream/enable`, `setting/stream/address`, `setting/stream/tag`, `setting/stream/queue-size`, `setting/stream/keep-latest-output` | as the inputs | What `control/subscribe/execute` or `control/unsubscribe/execute` applied last, as the settings file keeps it. Read-only. |
| `setting/settings-hash` | string | The hash of what the results are made with, as 16 hex digits. Read-only. See [The settings hash](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html#settings-hash). |

**Table 5. Outputs**

| Address | Type | Meaning |
| --- | --- | --- |
| `control/subscribe/output/stream/active` | bool | `true` while the stream runs. |
| `control/subscribe/output/stream/result` | flatbuffer `stream_template_matches` | The matches found in each frame, and the frame’s lineage. Subscribe to it to receive each one. See [The result of a frame](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html#result). |
| `control/subscribe/output/stream/last-failure` | string | Why the last frame that could not be searched failed. It names the source by its address, see [The result of a frame](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html#result). Emptied when the stream starts. |
| `control/subscribe/output/stream/statistics/…` | uint64 | Counters of the current or the last stream, see [Reading the statistics](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html#statistics). |

The stream publishes its results on `control/subscribe/output/stream/result`. Of the nodes of `find-template` it writes only `find-template/output/result`, and only with `keep-latest-output` on: `status-code` and `status-text` keep what the last call of the method left there.

## Setting it up {#setting-up}

1. Make sure the Cam Driver’s stream runs: its `hdvisionsystems/lumiscan-cam-driver/<camera name>/control/publish/output/stream/active` is `true`.
2. Set the inputs of `find-template` as for a single search, see [Finding a Template](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/finding-a-template.html). A call of `find-template/execute` on the camera’s `output/image` is a quick way to check them.
3. Write the camera’s stream folder, for example `hdvisionsystems/lumiscan-cam-driver/camera1/control/publish/output/stream`, to `control/subscribe/input/address`. Leave `control/subscribe/input/tag` empty to mark the results with the module id, or write a tag of your own to it.
4. Subscribe to `control/subscribe/output/stream/result`.
5. Set `control/subscribe/input/enable` to `true`, then write to `control/subscribe/execute`. Wait until `control/subscribe/output/stream/active` is `true`. The results arrive from then on.
6. To stop, set `control/subscribe/input/enable` to `false` and write to `control/subscribe/execute` again. The frame being searched is finished first.

On ctrlX OS, use the Data Layer view of the ctrlX OS web interface or your PLC program for these steps.

On a PC, the same steps with `krxclient`, the command line client of LumiScan Keryx that stands in for a PLC. Add the `--keryx-backend` and `--keryx-url` options your broker needs (see [krxclient](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/tools.html#krxclient)):

```none
krxclient write hdvisionsystems/lumiscan-template-finder/module-1/control/subscribe/input/address hdvisionsystems/lumiscan-cam-driver/camera1/control/publish/output/stream
krxclient write hdvisionsystems/lumiscan-template-finder/module-1/control/subscribe/input/enable true
krxclient execute hdvisionsystems/lumiscan-template-finder/module-1/control/subscribe/execute
krxclient subscribe hdvisionsystems/lumiscan-template-finder/module-1/control/subscribe/output/stream/result --count 5
```

`krxclient subscribe` shows a flatbuffer by its size only. It tells you that results arrive, not what they hold.

Good to know:

- Stream mode is a **level**, not a command, and the stream can be started before the Cam Driver’s stream: results arrive once frames do. See [Starting and stopping a stream](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/streams.html#running).
- What `control/subscribe/execute` applies is saved in the module’s settings file. After a restart of the application the module starts as it was: one that streamed streams again at once, without your program executing anything. See [Kept in the settings file](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html#saving).

## Changing the source {#subscribing}

A module takes one source. A PLC or another client changes it while the application runs, with or without a running stream:

1. Write the new values to the inputs of `control/subscribe` - only those you change: the others hold what is applied.
2. Write to `control/subscribe/execute`. The inputs are checked together, saved in the module’s settings file, and only then applied: `setting/stream/` shows them at once, and a running stream follows on its next cycle. Another address replaces the source; the frames the old one had waiting are counted as skipped. A new tag, queue size or `keep-latest-output` needs no new subscription: a new tag marks the next result.
3. To drop the source, write its address to `control/unsubscribe/input/address`, then write to `control/unsubscribe/execute`. Stream mode ends with it. The inputs of `control/subscribe` are set to what it applied: stream mode off, no address. The tag stays: it marks the module’s results, not the source.

When the settings file cannot be written, nothing changes. See [Kept in the settings file](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html#saving).

The methods answer with a result whose name depends on the Data Layer (see [Results of a method call](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/status-codes.html#method-results)):

| ctrlX Data Layer | LumiScan Keryx (PC) | When |
| --- | --- | --- |
| `DL_OK` | `Ok` | Done. |
| `DL_INVALID_VALUE` | `Rejected` | `control/subscribe/execute`: stream mode without an address, or a queue size outside `1` to `64`. `control/unsubscribe/execute`: the address is not the source, or there is no source. |
| `DL_CREATION_FAILED` | `CreationFailed` | The settings file could not be written, for example because it is not valid JSON. Nothing changed. |

These methods have no `status-text`. The reason for a refusal is written to the application log.

When the source cannot be subscribed to, the module tries it again every 5 seconds while the stream runs, and logs the first failure.

## The result of a frame {#result}

`control/subscribe/output/stream/result` holds a FlatBuffers table of type `stream_template_matches` (file identifier `HSTM`), registered on the Data Layer as `types/hdvisionsystems/lumiscan-template-finder/stream_template_matches`. Its compiled schema is installed as `bfbs/stream_template_matches.bfbs`.

| Field | Meaning |
| --- | --- |
| `lineage` | Where the result came from, see [The lineage of a result](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html#lineage). |
| `result` | The matches, as a `hdv.template_match.Result`: the same table `find-template` writes to `output/result` for the same picture, described in [Finding a Template](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/finding-a-template.html). `image_width` and `image_height` are the frame’s size. |

A read of `control/subscribe/output/stream/result` returns the latest result; before the first frame, an empty one. The last result stays after the stream stops.

A frame is decoded as `find-template` decodes the image node, so the same pixel formats are accepted, see [Requirements](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/requirements.html). A frame and the same picture read through `input/input-image-address` give the same matches.

A frame that cannot be searched gives no result. It is counted in `statistics/failed-frames`, and `control/subscribe/output/stream/last-failure` says why, for example:

```
a frame of 'hdvisionsystems/lumiscan-cam-driver/camera1/control/publish/output/stream' failed: invalid input: template-name is empty
```

The reasons are the ones `find-template` gives in its `status-text`: an input it would refuse, a template it cannot read, a crop region that does not fit the frame, a region smaller than the template.

## The lineage of a result {#lineage}

`lineage.steps` lists where the result came from, origin first:

1. The camera’s step, as the Cam Driver made it: `producer` is the camera’s address, `hdvisionsystems/lumiscan-cam-driver/<camera name>`; `run` when the camera’s stream started; `sequence` the frame’s number in that run; `external_id` the camera’s own frame number; `settings_hash` the camera’s settings; `tag` the Cam Driver’s tag for the camera, by default its module id, for example `camera1`.
2. The module’s step: `producer` is the module’s address, `hdvisionsystems/lumiscan-template-finder/<module-id>`; `run` when the module’s stream started (each start is a new run); `sequence` the result’s number in the run, from `1`; `settings_hash` the module’s settings, see [The settings hash](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html#settings-hash); `elapsed_us` the microseconds from the frame’s arrival at the module to its result, waiting included; `time_us` when the result was made, in microseconds since the epoch; `tag` the module’s tag, `control/subscribe/input/tag`, or the module id when it is empty.

So a result names its frame exactly: the camera by `producer`, the frame by `run` and `sequence`. To know which camera a result came from, read the `producer` of its first step. A gap in the camera step’s `sequence` between two results of the same camera is frames that were skipped, failed or lost.

A lineage holds at most 16 steps. A longer one keeps the origin and the newest steps, and `dropped` counts the steps left out.

A frame that carries no lineage gives a result with the module’s step alone. A value on a stream’s `frame` node that is not a `stream_image` is ignored, and logged once.

## The settings hash {#settings-hash}

`setting/settings-hash`, and the `settings_hash` of the module’s step in each result, identify what the results are made with. The node shows the hash as 16 hex digits; the step holds the same value as a number. The hash covers:

- every input of `find-template` the search reads, exactly as it was read for the frame - all of them but `input/input-image-address`;
- the template file, by its content: a new template saved under the old name is a new hash;
- the application’s name and version.

It does not cover stream mode, the source, the queue size or keep-latest-output: they choose and pace the frames, they do not change what is found in them.

`setting/settings-hash` is updated about every half second, also while the stream is off. The first time a hash appears, the module writes the settings it stands for to `settings-history/<module-id>-<hash>.json` in the application’s configuration directory, so a hash found in a result can be looked up later. The application does not delete these files. A file looks like this, shortened:

```json
{
    "format": 1,
    "settings": {
        "find-template/input/match-thresh": 0.9,
        "find-template/input/template-name": "screw",
        "find-template/template": {
            "file": "<configuration directory>/templates/screw.png",
            "fnv1a64": "<16 hex digits>"
        },
        "software.name": "lumiscan-template-finder",
        "software.version": "<version>"
    },
    "settingsHash": "<16 hex digits>"
}
```

> [!NOTE]
> A result carries the hash only. A different hash says that something the results are made with changed, not what changed. To find out, compare the two files in `settings-history` that the hashes name, by hand. Every input the search reads is hashed, so a change that does not alter a result can still change the hash.

## Reading the statistics {#statistics}

The counters start from zero each time the stream starts, are updated about four times a second while it runs, and keep their last values after it stops. All addresses start with `control/subscribe/output/stream/statistics/`.

| Counter | Meaning |
| --- | --- |
| `elapsed-ms` | Milliseconds since the stream started. Divide a counter by it for a rate. |
| `received-frames` | Frames the subscription delivered. |
| `processed-frames` | Frames searched, each with a result published on `control/subscribe/output/stream/result`. |
| `skipped-frames` | Frames never searched: pushed out of the queue by newer ones while a frame was searched (see [The queue size](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html#queue-size)), or waiting when the source was replaced or dropped. |
| `failed-frames` | Frames that could not be searched. `control/subscribe/output/stream/last-failure` says why the last one failed, and the log names the failures, at most one line every 5 seconds. |
| `lost-frames` | Frames dropped before they arrived, counted from gaps in the camera’s `sequence` within one run of its stream. A new source, or a new run of the camera’s stream, starts the count again. |
| `processing-us` | Microseconds all searches took, summed, without the time a frame waited for `find-template`. Divide by `processed-frames` for the mean. |

Frames still waiting when the stream stops are dropped without being counted.

## Kept in the settings file {#saving}

Stream mode and the source are settings of the module. They are kept in the `stream` member of the module’s settings file, `<module-id>.json` in the application’s configuration directory - the file `system/save-module-inputs` writes the inputs to.

`control/subscribe/execute` and `control/unsubscribe/execute` save what they apply there themselves, all five values in one write, before they apply them. When the file cannot be written, the method answers `CreationFailed` (ctrlX: `DL_CREATION_FAILED`) and nothing changes. After a restart the module subscribes to the same source and, when `stream.enable` is `true`, starts its stream at once: nobody needs to execute anything.

Saving changes only the `stream` member; the rest of the file stays as it was. The module makes the file when there is none yet - a module whose inputs were never saved has none. `system/save-module-inputs` in turn keeps the `stream` member when it rewrites the file; the inputs of `control/subscribe` are not saved as the module’s inputs.

| Platform | Configuration directory |
| --- | --- |
| ctrlX OS | `/var/snap/rexroth-solutions/common/solutions/activeConfiguration/lumiscan-template-finder` |
| PC (Windows) | `%APP_RESOURCE_DIR%\etc\lumiscan-template-finder`; without `APP_RESOURCE_DIR`, `C:\ProgramData\HD Vision Systems GmbH\LumiScan Vision Suite\lumiscan-templ-find\etc\lumiscan-template-finder` |

The `stream` member, beside the inputs of `find-template` (shortened here):

```json
{
    "find-template": {
        "template-name": "screw"
    },
    "stream": {
        "enable": true,
        "address": "hdvisionsystems/lumiscan-cam-driver/camera1/control/publish/output/stream",
        "queueSize": 1,
        "keepLatestOutput": false
    }
}
```

| Key | Required | Meaning |
| --- | --- | --- |
| `enable` | No | Stream mode: `true` starts the stream at the start of the application. Needs an `address`. `false` if left out. |
| `address` | No | The one source: a camera’s stream folder. |
| `tag` | No | What marks the module’s results: the `tag` of the module’s step in their lineage. The module id if left out. |
| `queueSize` | No | How many frames may wait: `1` to `64`, `1` if left out. |
| `keepLatestOutput` | No | `true` to write each stream result to `find-template/output/result` as well. `false` if left out. |
| `onEntry` | No | The steps applied to each frame as it arrives, each an object with a `kind`, as every LumiScan application’s `stream` has them. This application has none yet: leave it out, or empty (`[]`). A step starts the module out of stream mode, with a warning in the log; saving keeps it. |

`control/subscribe/execute` and `control/unsubscribe/execute` write all five.

Good to know:

- The file is read once, when the module is restored at the start of the application: a module in the saved module list, or `module-1` on a fresh installation. Changes made to the file by hand take effect at the next start.
- A module made with `system/create-module` starts with the stream off, no source, a queue size of `1` and `keep-latest-output` off, whatever a file of its name holds. What it applies from then on is saved to that file.
- To have a module and its stream back after a restart, save the module list too, with `system/save-current-modules`. Saving a list that no longer names a module deletes that module’s file, and its stream settings with it. See [Module Management](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/module-management.html).
- A value that cannot be used is ignored, and logged: an `enable` or `keepLatestOutput` that is not `true` or `false`, an `address` or `tag` that is not a string, a `queueSize` outside `1` to `64` (`1` is used). Stream mode without an `address` is ignored: the module starts out of stream mode.
- The `subscriptions` member of earlier versions is no longer read, and the module logs that it moved: give the source as `address`.

> [!WARNING]
> Do not add comments to `<module-id>.json`. The stream reads a file with comments, but the module’s inputs are then not restored at start: the log reports the file as unreadable.

## The queue size {#queue-size}

`control/subscribe/input/queue-size` sets how many frames may wait while a frame is searched: `1` to `64`, `1` by default. It is saved as `stream.queueSize`, and `setting/stream/queue-size` shows the value in use. A frame that arrives when that many wait pushes out the oldest of them, which is counted in `statistics/skipped-frames`. A new queue size applies from the next frame that arrives, with no new subscription.

| Queue size | Effect |
| --- | --- |
| 1 (default) | The module searches the newest frame. It never falls behind; when the search is slower than the camera, it skips frames. |
| More than 1 | Short bursts of frames are all searched, and fewer are skipped. When the search is slower than the camera for longer, the module falls behind: it searches frames up to that many searches old. Each waiting frame holds a whole image in memory. |

## Keeping the latest output {#keep-latest-output}

With `control/subscribe/input/keep-latest-output` `true` - applied by `control/subscribe/execute`, saved as `stream.keepLatestOutput` - the module also writes each stream result to `find-template/output/result`, as `find-template/execute` writes it, once the result is published on `control/subscribe/output/stream/result`. A client that reads `find-template/output/result` then has the newest frame’s result without subscribing to the stream. `status-code` and `status-text` are not written: they keep what the last call of `find-template` left there. It costs a copy of each result. Off by default.

## find-template while the stream runs {#while-streaming}

The stream and `find-template` use the same inputs, and they never run at the same time on one module:

- A frame that arrives while `find-template` runs waits until the method has finished. It is delayed, not failed.
- A call of `find-template/execute` while a frame is searched answers busy: `output/status-code` is `-1`, the write answers `TooManyOperations` (ctrlX: `DL_TOO_MANY_OPERATIONS`), and nothing is done. `output/result` keeps its value, as for any busy call (see [Execute a Method](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/execute-a-method.html)). With a camera streaming, this happens often. Stop the stream before you call the method, or call it again.
- `system/remove-module` also answers busy (`-1`) while a frame of that module is searched. Stop the stream first. Removing a module stops its stream.
- `system/create-template` has a lock of its own and is not held up by the stream.

Other modules are not affected: each module has its own lock and its own stream.

## Limitations {#limitations}

- The stream has been tested on Windows with LumiScan Keryx and simulated images only. It has not been verified on Linux - on ctrlX OS or Ubuntu - on the ctrlX Data Layer, or with a real camera.
- LumiScan Cockpit does not draw the stream’s results yet.
- Changes made to the settings file by hand take effect at the next start of the application.
- The hash covers every input the search reads. It changes with some edits that do not change a result.

# Tuning the Search – LumiScan Template Finder

URL: https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/tuning-the-search.html

All of these are inputs of `find-template`. The defaults search the template at its original size and orientation, which is the fastest configuration and the right starting point.

## Search range

| Node | Type | Default | Description |
| --- | --- | --- | --- |
| `input/scale/min-scale` | double | `1.0` | Smallest template scaling factor. Must be greater than 0 |
| `input/scale/max-scale` | double | `1.0` | Largest template scaling factor |
| `input/scale/step-scale` | double | `1.0` | Increment between the scales searched |
| `input/rotation/min-rot` | double | `0.0` | Smallest rotation in degrees, 0 to 360 |
| `input/rotation/max-rot` | double | `0.0` | Largest rotation in degrees, 0 to 360 |
| `input/rotation/step-rot` | double | `1.0` | Increment between the rotations searched. Must be greater than 0 |

Setting the minimum equal to the maximum searches that single value and ignores the step.

> [!IMPORTANT]
> The work is **one pass per combination**. Searching 5 scales and 36 rotations is 180 passes over the image, not 41. Widen a range only as far as the parts actually vary, and prefer a coarse step: a rotation step of 5 degrees usually locates a part well enough for a follow-up measurement.

## Matching

| Node | Type | Default | Description |
| --- | --- | --- | --- |
| `input/match-thresh` | double | `0.9` | Minimum acceptable score, 0 to 1 |
| `input/match-mode` | string | `TM_SQDIFF_NORMED` | Matching algorithm |
| `input/use-grayscale` | bool | `true` | Match on grayscale when the images have colour |

`match-mode` accepts `TM_SQDIFF`, `TM_SQDIFF_NORMED`, `TM_CCORR`, `TM_CCORR_NORMED`, `TM_CCOEFF` and `TM_CCOEFF_NORMED`. Scores from different modes are not comparable, which is why the mode used is included in the result.

`use-grayscale` makes matching roughly three times faster by not correlating each colour channel separately, and costs little accuracy in most industrial scenes. Turn it off when colour is what distinguishes the part.

## Understanding the confidence

The confidence is **not** an absolute measure of similarity. The score map is rescaled once for every scale/rotation step, which has two consequences worth knowing:

- The best location of **every** step reaches a confidence near 1, even when that step’s scale fits nothing in the image.
- `match-thresh` therefore acts **per step** rather than globally, as soon as you search a range.

A single-scale, single-rotation search behaves as you would expect. A wide search can report weak matches at unrelated places alongside the real one. The true match is still the highest-confidence entry, at index 0.

If you see spurious matches, raise `match-thresh` or narrow the range.

The application also removes duplicates: without that, a search over 10 steps would report the same part up to 10 times. Only repeats at the **same location** are removed, which is why a weak match somewhere else can still appear.

## Pre-processing

| Node | Type | Default | Description |
| --- | --- | --- | --- |
| `input/preprocess/blur-sigma-x` | double | `1.0` | Gaussian blur strength in X. 0 or less turns blurring off |
| `input/preprocess/blur-sigma-y` | double | `0.0` | Blur strength in Y. 0 means the same as X |
| `input/preprocess/blur-kernel-size-x` | uint32 | `0` | Blur kernel width. 0 derives it from the blur strength; otherwise an odd number |
| `input/preprocess/blur-kernel-size-y` | uint32 | `0` | Blur kernel height. 0 derives it from the blur strength; otherwise an odd number |
| `input/preprocess/bin-size` | int32 | `1` | Shrink both images by this factor before matching. 1 turns it off |

Blurring suppresses sensor noise, at the cost of some positional precision. The default is a mild blur that suits most cameras.

Binning is the most effective speed control: matching cost falls with the square of the factor, so a bin size of 2 is roughly four times faster. The limit is the template - once a distinguishing feature shrinks below a few pixels it stops being distinguishable. Small or thin templates should stay at 1.

## A practical order

1. Start at the defaults and search for a template cut from the same setup. Confirm it is found.
2. If the parts vary in orientation, widen the rotation range with a coarse step.
3. If they vary in distance, widen the scale range.
4. If it is too slow, raise `bin-size` to 2 and check the confidence is still acceptable.
5. If spurious matches appear, raise `match-thresh`.

# Template Storage – LumiScan Template Finder

URL: https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/template-storage.html

Templates are ordinary PNG files kept in the application’s configuration directory. You can inspect, copy and back them up with normal tools, and a template prepared elsewhere can simply be uploaded (ctrlX OS) or copied in (PC).

## Where they are

The configuration directory, and a `templates` folder inside it, are created when the application first starts, so there is somewhere to upload or copy to on a brand-new installation. Where it is depends on the platform.

### On ctrlX OS

On a ctrlX device the configuration directory is part of the **active solution**:

```
/var/snap/rexroth-solutions/common/solutions/activeConfiguration/lumiscan-template-finder
```

Because it belongs to the solution, templates are included when the solution is exported and are restored with it on another device.

### On a PC

On Windows the configuration directory is `%APP_RESOURCE_DIR%\etc\lumiscan-template-finder`; without `APP_RESOURCE_DIR`, `C:\ProgramData\HD Vision Systems GmbH\LumiScan Vision Suite\lumiscan-templ-find\etc\lumiscan-template-finder`.

## Layout

```
<configuration directory>/
├── lumiscan-template-finder.json   module list, chosen template folder, log level
├── module-1.json                   saved settings of one module
└── templates/                      default template folder
    ├── screw.png
    └── bracket.png
```

**One folder serves the whole application**, not one per module: every module searches it, and `create-template` writes into it, so a template created by one module is immediately usable by all of them.

`module-1.json` is written by `system/save-module-inputs` - see [Module Management](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/module-management.html).

## Log level

`lumiscan-template-finder.json` also carries how much the application logs, in the same `system` block the other LumiScan applications use:

```json
{
    "system": {
        "logLevel": "TRACE"
    }
}
```

`TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `FATAL` and `OFF` are accepted, from most detail to none. `TRACE` is what to set before reproducing a problem for a support report.

The level is read **once, at startup**, so restart the application after changing it. Add the block by hand: the application only ever writes `template-dir` and `modules` to this file, and leaves everything else in it alone.

The key is optional. Without it the application logs at its built-in `DEBUG` level, and a value that is not one of the names above is reported in the log and changes nothing - a typo here can never silence the application.

## Choosing the folder

```
system/template-dir                          read-only, the folder in use
system/templates                             read-only, what is in it
system/set-template-dir/execute              change it
system/set-template-dir/input/template-dir   the folder to change to
```

`template-dir` and `templates` are **read-only outputs** of `set-template-dir`, so the listing can never disagree with the folder it came from. To change folder, write `set-template-dir/input/template-dir`, then execute the method, then check `set-template-dir/output/status-code` is `1`.

The folder must already exist. It is **not** created for you: the default `templates` is created at startup, so a missing folder means the name is wrong, and quietly creating an empty one would hide the mistake. The choice is saved and restored on the next start.

If the call is rejected nothing changes - the application keeps using the folder it had.

### system/templates

Every template in the folder, **without the `.png` extension**, sorted:

```
["bracket", "screw"]
```

An entry can be pasted straight into `find-template/input/template-name`. The list is refreshed at startup, when `set-template-dir` succeeds, and when `create-template` saves a new template.

> [!NOTE]
> It is **not** refreshed when a file arrives by other means, such as an upload through the ctrlX web interface (ctrlX OS) or a file copied into the folder (PC). Execute `set-template-dir` again, naming the same folder, to pick such a file up.
>
> Only files ending in a lower case `.png` are listed. `SCREW.PNG` is ignored.

## Getting templates onto the device

- **From a live image:** [Creating a Template](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/creating-a-template.html) writes the file directly. No file transfer needed.
- **Through the ctrlX web interface (ctrlX OS):** The application’s data folder is browsable, so a prepared PNG can be uploaded into `templates`.
- **With the solution (ctrlX OS):** Templates stored in the active solution’s configuration travel with it to another device.
- **By copying (PC):** A prepared PNG can be copied into `templates` in the configuration directory.

A template added while the application is running is picked up on the next search - the file is read each time, not cached at startup, so there is no need to restart.

## File format

- PNG, 8-bit RGB. Created templates are always written this way, whatever the camera’s pixel format.
- A grayscale PNG works too.
- `.png` is added when the name has no extension, so `screw` and `screw.png` mean the same file.

## Path rules

Folder and file names are always interpreted **relative to the configuration directory**. Two things are rejected with status code `-2`:

- an absolute path, such as `/tmp/templates`
- a path that leads outside the configuration directory, such as `../../etc`

This means the application can only ever read and write inside its own configuration directory. A path that stays inside is fine even if it contains `..`.

## Troubleshooting

Problems with the template folder and the template files are described step by step in [Troubleshooting](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html):

- [Status code `-4` (source not found)](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#faq-status-minus-4) - naming a directory or a file, or a file that is there but is not found
- [Status code `-2` (invalid input)](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#faq-status-minus-2) - an absolute path, or one pointing outside the configuration directory
- [Status code `-6` (write failed)](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#ts-status-minus-6)
- [The template file is on the device but missing from `system/templates`](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#faq-template-not-listed)

## Starting from an Example (PC) {#generate-settings}

On a PC, the Template Finder writes an example of its settings into a folder of your choice, and ends without starting. For example, on Windows:

```shell
lumiscan-templ-find --generate-settings C:\work\template-finder-settings
```

Without a folder (`-g` alone) it writes into the current folder. The example is the application settings file `lumiscan-template-finder.json`, which names the module `module-1`, and the module file `module-1.json` beside it: every input of `find-template` with the value it has by default, except the image address, which is the Cam Driver’s `camera1`. Beside them, in `schemas/`, are the schemas the two files name in `"$schema"`: `lumiscan-template-finder.schema.json`, `lumiscan-template-finder-module.schema.json`, and `stream.schema.json` for the `stream` section of a module file. They describe every key the Template Finder reads - each input of `find-template` with its type, its default and the range a run accepts - so an editor that understands JSON Schema can check the files and show what each value means. Copy the `schemas` folder along with the files: `system/save-module-inputs` keeps the `"$schema"` of a module file it saves. Existing files are never overwritten: when one of them is in the folder already, nothing is written and the Template Finder says which.

The Template Finder then names the folder it reads its settings from - on Windows by default `C:\ProgramData\HD Vision Systems GmbH\LumiScan Vision Suite\lumiscan-templ-find\etc\lumiscan-template-finder`. Edit the example, copy it there, and start the Template Finder. See also [Where the files are (Windows)](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/keryx.html#files).

# Module Management – LumiScan Template Finder

URL: https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/module-management.html

A **module** is one configured instance of the application. It owns the matching operation, with its own settings and results:

```
hdvisionsystems/lumiscan-template-finder/<module-id>/find-template/...
```

Creating a template is **not** per module: it writes into the one directory every module shares, so it lives on the system node as `system/create-template`. See [Creating a Template](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/creating-a-template.html).

Modules can be created and removed while the application runs. A fresh installation serves one module, named `module-1`.

> [!IMPORTANT]
> **On ctrlX OS, one licence covers ten modules.** The eleventh module acquires a second licence of the same key, and a module is refused with status `-11` when no licence on the device covers it.

The management node sits outside the modules:

```
hdvisionsystems/lumiscan-template-finder/system/
```

## Nodes

| Node | Type | Description |
| --- | --- | --- |
| `modules` | string array | The modules that currently exist |
| `create-template/execute` | method | Cut a template out of a live image and save it into `template-dir`, for every module to use. See [Creating a Template](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/creating-a-template.html) |
| `create-module/execute` | method | Create a module and its node subtree |
| `create-module/input/module-id` | string | Name of the module to create. Lower case letters, digits, `-` and `_` only; must not be `system` and must not already exist |
| `remove-module/execute` | method | Remove a module and its node subtree |
| `remove-module/input/module-id` | string | Name of the module to remove |
| `save-current-modules/execute` | method | Persist the module list, so the same modules are recreated on the next start |
| `save-module-inputs/execute` | method | Persist one module’s settings |
| `save-module-inputs/input/module-id` | string | Name of the module whose settings to save |

Every method also has `output/status-code` and `output/status-text`.

## Creating a module

1. Set `system/create-module/input/module-id` to the new name
2. Write to `system/create-module/execute`
3. Check `system/create-module/output/status-code` is `1`

The module is live at once, with default settings, and appears in `system/modules`. It is **not** permanent until the module list is saved.

Removing a module is the mirror image, through `remove-module`. A module is refused with `-1` (busy) while one of its own operations is running, rather than having its nodes destroyed mid-execution.

> [!NOTE]
> A module created now is a **new** module: it starts with the default input values, even if a module of that name existed before and its settings were saved. Those settings stay on disk until the removal is made permanent - `save-current-modules` deletes the saved inputs of every module the new list no longer names, because until the list is written a removal is not permanent and a restart brings the module back with its settings intact.

## Saving

Two things are saved separately, and both must be saved to survive a restart:

- **the module list** - `save-current-modules`, so the same modules are recreated;
- **each module’s settings** - `save-module-inputs`, once per module.

To save a module’s settings:

1. Set `system/save-module-inputs/input/module-id`
2. Write to `system/save-module-inputs/execute`
3. Check `system/save-module-inputs/output/status-code` is `1`

Every input of that module is written to the application configuration directory and restored on the next start. Results are not saved - they are produced by the next run. A module’s image stream settings are saved in the same file, by the stream’s own methods - see [Kept in the settings file](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html#saving).

A setting whose node no longer exists after a software update is skipped with a log entry, so an older configuration never prevents the application from starting.

## Why the address contains a module even with one module

The `<module-id>` level is always present, so addresses do not change when a second module is added: a program written today against `module-1` keeps working. It also matches the path convention the other LumiScan applications document, see [Addresses and Modules](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/addresses.html). How the finders' modules differ from those of the Cam Driver, AI Object Matching and Calibration is summarised in [Settings, Modules and Restart](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/settings-and-modules.html#registry-apps).

## What is shared between modules

Modules are independent in everything except templates. `system/template-dir` names one directory for the whole application, `system/create-template` writes into it, and every module searches it, so a template only ever has to be created once. See [Template Storage](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/template-storage.html).

# Data Layer Reference – LumiScan Template Finder

URL: https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/datalayer-reference.html

Complete node listing. All paths start with:

```
hdvisionsystems/lumiscan-template-finder/
```

## Data Layer {#data-layer}

LumiScan Template Finder offers its functions on the Data Layer under `hdvisionsystems/lumiscan-template-finder`.

On ctrlX OS (ctrlX CORE or ctrlX IPC), LumiScan Template Finder uses the [ctrlX Data Layer](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/ctrlx-data-layer.html).

On a PC with Windows 11 or Ubuntu 24.04, LumiScan Template Finder uses [LumiScan Keryx](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/keryx.html).

The node addresses, types and call patterns are the same on both. LumiScan Template Finder offers:

- [execute methods](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/execute.html)
- a [stream](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/streams.html) subscription to one source (experimental)

How addresses are built, how to call functions, the status codes and the tools are described in [LumiScan Keryx](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/index.html).

## Address pattern

```
hdvisionsystems/lumiscan-template-finder/
├── system/                              application-wide management
│   ├── modules
│   ├── template-dir                     the one directory templates live in
│   ├── templates                        what is in it
│   ├── set-template-dir/
│   ├── create-template/                 application-wide, not per module
│   ├── create-module/
│   ├── remove-module/
│   ├── save-current-modules/
│   ├── save-module-inputs/
│   └── meta/subscription-schema         what the stream's source must hold
└── <module-id>/                         one per configured instance, e.g. module-1
    ├── find-template/
    │   ├── execute
    │   ├── input/...
    │   └── output/{result, status-code, status-text}
    ├── control/subscribe/               the image stream (experimental)
    │   ├── execute
    │   ├── input/{enable, address, tag, queue-size, keep-latest-output}
    │   └── output/stream/...
    ├── control/unsubscribe/{execute, input/address}
    └── setting/{stream, settings-hash}
```

Every operation has `execute`, `output/status-code` and `output/status-text`. Anything else under `output/` is present only where the operation has more to report.

> [!NOTE]
> A fresh installation serves one module, `module-1`, and more can be created at runtime. On ctrlX OS, one licence covers ten modules. See [Module Management](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/module-management.html).

## system

| Node | Type | Description |
| --- | --- | --- |
| `system/modules` | string array | The modules that currently exist |
| `system/template-dir` | string | Directory every module reads templates from and writes them to, relative to the configuration directory. Read-only - change it with `set-template-dir` |
| `system/templates` | string array | Templates available in that directory, without the `.png` extension. Read-only |
| `system/set-template-dir/execute` | method | Point the application at another template directory |
| `system/set-template-dir/input/template-dir` | string | Directory to switch to. It must already exist |
| `system/create-template/execute` | method | Cut a template out of a live image and save it into `template-dir`. Application-wide: the template is usable by every module. Its inputs and outputs are listed under [system/create-template](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/datalayer-reference.html#system_create_template) |
| `system/create-module/execute` | method | Create a module and its node subtree |
| `system/create-module/input/module-id` | string | Name of the module to create |
| `system/remove-module/execute` | method | Remove a module and its node subtree |
| `system/remove-module/input/module-id` | string | Name of the module to remove |
| `system/save-current-modules/execute` | method | Persist the module list, so the same modules return after a restart |
| `system/save-module-inputs/execute` | method | Persist one module’s inputs |
| `system/save-module-inputs/input/module-id` | string | Module whose inputs to persist |
| `system/meta/subscription-schema` | string | What the node a module subscribes to must hold, as a JSON Schema (draft-04) of its JSON form: here a `stream_image`, the `frame` node of the stream folder, with `lineage` and `image`. The same for every module. Read-only. Experimental |

## \<module-id>/find-template

### Inputs

| Node | Type | Default | Description |
| --- | --- | --- | --- |
| `input/input-image-address` | string | *(empty)* | Address of the image node to search |
| `input/template-name` | string | *(empty)* | Template to search for, as listed on `system/templates`. `.png` is appended when no extension is given |
| `input/crop/startX` | uint16 | `0` | Left edge of the region to search, pixels |
| `input/crop/startY` | uint16 | `0` | Top edge of the region to search, pixels |
| `input/crop/width` | uint16 | `0` | Width of the region. `0` reaches the right edge |
| `input/crop/height` | uint16 | `0` | Height of the region. `0` reaches the bottom edge |
| `input/result-coordinate` | string | `IMAGE` | `IMAGE` or `CROP`: which image the positions in the result are measured against |
| `input/scale/min-scale` | double | `1.0` | Smallest scaling factor |
| `input/scale/max-scale` | double | `1.0` | Largest scaling factor |
| `input/scale/step-scale` | double | `1.0` | Increment between scales |
| `input/rotation/min-rot` | double | `0.0` | Smallest rotation, degrees |
| `input/rotation/max-rot` | double | `0.0` | Largest rotation, degrees |
| `input/rotation/step-rot` | double | `1.0` | Increment between rotations, degrees |
| `input/match-thresh` | double | `0.9` | Minimum acceptable score, 0-1 |
| `input/match-mode` | string | `TM_SQDIFF_NORMED` | Matching algorithm |
| `input/use-grayscale` | bool | `true` | Match on grayscale |
| `input/preprocess/blur-sigma-x` | double | `1.0` | Blur strength in X; 0 or less disables |
| `input/preprocess/blur-sigma-y` | double | `0.0` | Blur strength in Y; 0 means same as X |
| `input/preprocess/blur-kernel-size-x` | uint32 | `0` | Blur kernel width; 0 derives from strength |
| `input/preprocess/blur-kernel-size-y` | uint32 | `0` | Blur kernel height; 0 derives from strength |
| `input/preprocess/bin-size` | int32 | `1` | Downsample factor; 1 disables |

### Outputs

| Node | Type | Description |
| --- | --- | --- |
| `output/result` | flatbuffer | Matches, sorted by confidence |
| `output/status-code` | int16 | Execution status |
| `output/status-text` | string | Outcome in words |

## \<module-id> image stream (experimental) {#module_stream}

The addresses below are relative to `<module-id>/`, beside `find-template/`. The stream searches each frame with the inputs of `find-template`, all but `input/input-image-address`. See [Finding Templates on an Image Stream](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html).

### Inputs

| Node | Type | Default | Description |
| --- | --- | --- | --- |
| `control/subscribe/input/enable` | bool | as applied | Stream mode: `true` runs the stream, `false` stops it |
| `control/subscribe/input/address` | string | as applied | The one source, a camera’s stream folder, e.g. `hdvisionsystems/lumiscan-cam-driver/camera1/control/publish/output/stream`. Another address replaces it |
| `control/subscribe/input/tag` | string | as applied | The tag on the module’s results: the module’s step in the lineage of each stream result carries it. Empty: the module id, e.g. `module-1`. A new tag keeps the source; the next result carries it |
| `control/subscribe/input/queue-size` | uint32 | as applied | Frames that may wait while one is searched, 1-64 |
| `control/subscribe/input/keep-latest-output` | bool | as applied | `true` also writes each stream result to `find-template/output/result` |
| `control/unsubscribe/input/address` | string | (empty) | The source to drop, as `setting/stream/address` shows it |

### Methods

| Node | Type | Description |
| --- | --- | --- |
| `control/subscribe/execute` | method | Check the inputs of `control/subscribe` together, save them in `<module-id>.json` as `stream`, then apply them. Writing an input alone changes nothing |
| `control/unsubscribe/execute` | method | Drop the source named by `control/unsubscribe/input/address`, which ends stream mode; the tag stays. Saved in `<module-id>.json` like a subscribe |

### Settings and outputs

| Node | Type | Description |
| --- | --- | --- |
| `setting/stream/{enable, address, tag, queue-size, keep-latest-output}` | as the inputs | What `control/subscribe/execute` or `control/unsubscribe/execute` applied last. Read-only |
| `setting/settings-hash` | string | Hash of what the results are made with, 16 hex digits. Read-only |
| `control/subscribe/output/stream/active` | bool | `true` while the stream runs |
| `control/subscribe/output/stream/result` | flatbuffer | One `stream_template_matches` per searched frame. Subscribe to receive each one |
| `control/subscribe/output/stream/last-failure` | string | Why the last frame that could not be searched failed, naming the source by its address |
| `control/subscribe/output/stream/statistics/elapsed-ms` | uint64 | Milliseconds since the stream started |
| `control/subscribe/output/stream/statistics/received-frames` | uint64 | Frames the subscription delivered |
| `control/subscribe/output/stream/statistics/processed-frames` | uint64 | Frames searched, each with a result |
| `control/subscribe/output/stream/statistics/skipped-frames` | uint64 | Frames pushed out of the queue, or waiting when the source was replaced or dropped |
| `control/subscribe/output/stream/statistics/failed-frames` | uint64 | Frames that could not be searched |
| `control/subscribe/output/stream/statistics/lost-frames` | uint64 | Frames lost before they arrived |
| `control/subscribe/output/stream/statistics/processing-us` | uint64 | Search time of all searched frames, summed, microseconds |

The inputs of `control/subscribe` start with what is applied, and only `control/subscribe/execute` applies them. `control/subscribe/execute` is refused for stream mode without an address or a queue size outside 1-64, `control/unsubscribe/execute` for an address that is not the source (`Rejected`, ctrlX: `DL_INVALID_VALUE`). When `<module-id>.json` cannot be written, both answer `CreationFailed` (ctrlX: `DL_CREATION_FAILED`) and change nothing. The stream nodes are the same in every consumer, see [Streams](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/streams.html#consumer).

## system/create-template {#system_create_template}

### Inputs

| Node | Type | Default | Description |
| --- | --- | --- | --- |
| `input/input-image-address` | string | *(empty)* | Address of the image node to cut from |
| `input/crop/startX` | int32 | `0` | Left edge of the region, pixels |
| `input/crop/startY` | int32 | `0` | Top edge of the region, pixels |
| `input/crop/width` | int32 | `0` | Width of the region, pixels |
| `input/crop/height` | int32 | `0` | Height of the region, pixels |
| `input/template-name` | string | *(empty)* | Name to save under, inside `system/template-dir`. Use lower case: only lower case `.png` files are listed |

### Outputs

| Node | Type | Description |
| --- | --- | --- |
| `output/template-path` | string | Path of the written file, relative to the configuration directory |
| `output/status-code` | int16 | Execution status |
| `output/status-text` | string | Outcome in words |

## Result flatbuffer

`output/result` is a `hdv.template_match.Result`:

| Field | Type | Description |
| --- | --- | --- |
| `matches` | array of `Match` | One entry per occurrence, sorted by confidence |
| `best_index` | ulong | Index of the best match; always 0 |
| `best_score` | float | Confidence of the best match; 0.0 if none |
| `template_name` | string | Template used |
| `match_mode` | string | Algorithm used |
| `match_thresh` | float | Threshold applied |
| `image_width` | uint | Width of the searched image |
| `image_height` | uint | Height of the searched image |
| `timestamp` | ulong | Microseconds since the epoch |

`Match`:

| Field | Type | Description |
| --- | --- | --- |
| `oriented_bounding_box` | struct | `center_x`, `center_y`, `width`, `height` in pixels; `angle` in degrees |
| `confidence` | float | Score, 0-1 |
| `scale` | float | Scaling factor of this match |
| `rotation` | float | Rotation of this match, degrees |

`control/subscribe/output/stream/result` is a `hdv.stream.StreamTemplateMatches` (`stream_template_matches`, registered as `types/hdvisionsystems/lumiscan-template-finder/stream_template_matches`): `lineage`, where the frame came from, and `result`, the `hdv.template_match.Result` above.

## Image node expected at `input-image-address`

The address must name an image node of **another** application on the same device - the same ctrlX CORE or ctrlX IPC, or the same PC - providing:

| Child | Type | Description |
| --- | --- | --- |
| `data` | array of uint8 | Raw pixel data |
| `width` | uint64 | Width in pixels |
| `height` | uint64 | Height in pixels |
| `pixel-type` | string | GenICam pixel format name |

An address inside this application is rejected with status code `-2`.

## Status codes

See [Execution Status](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/execution-status.html) for the full table. Negative is always an error; `0` means not yet run; positive means success. These are the finders' own codes, not the module status of the other LumiScan apps, see [Execution status of the finders](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/status-codes.html#execution-status).

# FAQ – LumiScan Template Finder

URL: https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/faq.html

Short answers to common questions about LumiScan Template Finder. Each entry links to the page with the details.

> [!TIP]
> Each entry has a fixed anchor (for example `#faq-pixel-formats`). Problems, error messages and status codes are described step by step in [Troubleshooting](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html).

## Requirements and setup

### On which platforms does the Template Finder run, and which Data Layer does it use? {#faq-platforms}

- **Answer:** On ctrlX OS (ctrlX CORE or ctrlX IPC) it uses the ctrlX Data Layer; on a PC with Windows 11 or Ubuntu 24.04 it uses LumiScan Keryx, the Data Layer of HD Vision Systems for PCs. The node addresses, types and the way the methods are called are the same on both, so a program written against one works against the other. Only the names of the results of a method call differ, for example `DL_TOO_MANY_OPERATIONS` on the ctrlX Data Layer and `TooManyOperations` on LumiScan Keryx.
- **More:** [Data Layer Reference](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/datalayer-reference.html), [ctrlX Data Layer and LumiScan Keryx](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/platforms.html)

### Which image source does the Template Finder need? {#faq-image-source}

- **Answer:** The application does not talk to a camera itself. It reads the image node of another application that runs on the **same device** - the same ctrlX CORE or ctrlX IPC, or the same PC (remote Data Layer access is not supported), normally LumiScan Cam Driver, for example `hdvisionsystems/lumiscan-cam-driver/camera1/output/image`. Any application works if its image node provides `data` (raw, uncompressed uint8 pixel data), `width`, `height` and `pixel-type` (GenICam pixel format name). An address inside the Template Finder itself is rejected with status code `-2`.
- **More:** [Requirements](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/requirements.html), [Data Layer Reference](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/datalayer-reference.html)

### Which pixel formats are supported? {#faq-pixel-formats}

- **Answer:** `Mono8`, `Mono12`, `RGB8`, `RGB12`, `BGR8`, `BGR12`, `BayerGR8`, `BayerGR12`, `BayerRG8` and `BayerRG12`. Bayer images are converted to colour and 12-bit images are scaled down to 8 bit before matching, so templates cut from one format still match images of another. Any other pixel format is rejected with status code `-3`.
- **More:** [Requirements](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/requirements.html)

## Templates

### How do I create a template from a live camera image? {#faq-create-template}

- **Answer:** Use `system/create-template`, which is application-wide: it cuts a region out of the current image and saves it as a PNG that every module can use:
  - Make sure the camera application has captured an image.
  - Set `system/create-template/input/input-image-address`, the four `input/crop/` values (`width` and `height` must be greater than 0) and `input/template-name`. Use a lower case name; `.png` is added if you give no extension.
  - Write to `system/create-template/execute` and read `output/status-code`. On `1`, `output/template-path` names the file, for example `templates/screw.png`.
  - On `-5`, the region does not fit the image; `output/status-text` names the actual image size.
  - The file is written as 8-bit RGB PNG, whatever the camera’s pixel format. An existing file with the same name is overwritten without warning.
- **More:** [Creating a Template](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/creating-a-template.html), [How To: Match a Part from a Camera Image](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/how-tos/match-a-part-from-a-camera-image.html)

### Where are templates stored, and can I upload one prepared on a PC? {#faq-template-storage}

- **Answer:** Templates are PNG files in the `templates` folder of the application’s configuration directory, created at first start. A template added by hand is read on the next search, without a restart.
  - On ctrlX OS the directory is part of the active solution (`/var/snap/rexroth-solutions/common/solutions/activeConfiguration/lumiscan-template-finder`), so templates are exported and restored with the solution. A prepared PNG (8-bit RGB or grayscale) can be uploaded into it through the ctrlX web interface.
  - On a PC a prepared PNG is copied into the folder. On Windows the directory is `%APP_RESOURCE_DIR%\etc\lumiscan-template-finder`, or without `APP_RESOURCE_DIR` `C:\ProgramData\HD Vision Systems GmbH\LumiScan Vision Suite\lumiscan-templ-find\etc\lumiscan-template-finder`.
  - To use another folder, write `system/set-template-dir/input/template-dir`, execute `system/set-template-dir` and check that its status code is `1`. The folder must already exist; an absolute path or one leading outside the configuration directory is rejected with `-2`.
- **More:** [Template Storage](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/template-storage.html)

## Searching and tuning

### How do I run a search and read the result? {#faq-read-result}

- **Answer:** Set `find-template/input/input-image-address` and `find-template/input/template-name` (as listed on `system/templates`), write to `find-template/execute` and read `find-template/output/status-code`. The write is blocking and returns when the search has finished. On `1`, read `output/result`: `matches` is sorted by confidence, so `matches[0]` and `best_score` give the best match. Each match has an `oriented_bounding_box` (`center_x`, `center_y`, `width`, `height` in pixels, `angle` in degrees), `confidence`, `scale` and `rotation`. An empty `matches` list with status `1` is a normal result: the part was not found.
- **More:** [Finding a Template](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/finding-a-template.html)

### How can I make the search faster? {#faq-search-too-slow}

- **Answer:**
  - Search only as wide a scale and rotation range as the parts actually vary, with a coarse step.
  - Raise `input/preprocess/bin-size` to `2` (roughly four times faster) and check the confidence is still acceptable. Small or thin templates should stay at `1`.
  - Keep `input/use-grayscale` at `true` (roughly three times faster than matching each colour channel); turn it off only when colour distinguishes the part.
  - Limit the search to a region with `input/crop/`.
- **More:** [Tuning the Search](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/tuning-the-search.html), [Requirements](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/requirements.html)

### How do I search only part of the image, and which frame are the positions in? {#faq-search-region}

- **Answer:** Set `find-template/input/crop/` (`startX`, `startY`, `width`, `height`). A zero width or height reaches the right or bottom edge, so all zero searches the whole image. A region reaching past an edge is refused, not trimmed, with a message such as `crop/startX + crop/width (100 + 541 = 641) exceeds the image width 640`. `input/result-coordinate` decides the frame of the positions: `IMAGE` (default, the full image, usable directly for a robot pick) or `CROP` (the searched region, top left corner (0,0)).
- **More:** [Finding a Template](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/finding-a-template.html)

### Can the Template Finder search every frame a camera streams? {#faq-image-stream}

- **Answer:** Yes, as an experimental feature. A module subscribes to one camera’s stream and searches each frame with the inputs of `find-template` (all but `input/input-image-address`), publishing one result per frame on `<module-id>/control/subscribe/output/stream/result`:
  - Make sure the Cam Driver’s stream runs.
  - Write the camera’s stream folder, for example `hdvisionsystems/lumiscan-cam-driver/camera1/control/publish/output/stream`, to `<module-id>/control/subscribe/input/address`.
  - Set `control/subscribe/input/enable` to `true` and write to `control/subscribe/execute`. Writing `enable` alone starts nothing.
  - Wait until `control/subscribe/output/stream/active` is `true`.
  - What `control/subscribe/execute` applies is saved in `<module-id>.json`, so a module that streamed streams again after a restart. For a PLC, switch on `control/subscribe/input/keep-latest-output` and read `find-template/output/result`.
- **More:** [Finding Templates on an Image Stream (Experimental)](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html), [Streams (Experimental)](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/streams.html)

## Status codes and errors

### How do I know whether an operation worked, and where is the reason for a failure? {#faq-status-codes}

- **Answer:** Check the sign of `output/status-code`: greater than 0 is success, `0` means the operation has not run since the application started, less than 0 means it failed and produced nothing. The reason is on `output/status-text`, which starts with `ok:` or `error:`. A failed write to `execute` itself answers only with a status code (over REST, a bare `400`), so read `output/status-text` afterwards. The same text is written to the application log: on ctrlX OS in the ctrlX Logbook or with `journalctl`, on a PC in the application’s console output. `-1` (busy) means another operation of the same module was still running; nothing was done, so try again when it has finished.
- **More:** [Execute a Method](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/execute-a-method.html), [Execution Status](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/execution-status.html)

## Troubleshooting {#troubleshooting}

Problems and error messages are described step by step in [Troubleshooting](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html):

- [Status code `-1` (busy)](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#faq-busy-while-streaming)
- [Status code `-2` (invalid input)](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#faq-status-minus-2)
- [Status code `-3` (image read failed)](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#faq-status-minus-3)
- [Status code `-4` (source not found)](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#faq-status-minus-4)
- [The crop region does not fit the image](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#ts-crop-does-not-fit)
- [Status code `-6` (write failed)](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#ts-status-minus-6)
- [The result is empty although the status code is `1`](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#ts-empty-result)
- [The template is not found even in the image it was cut from](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#faq-not-found-in-own-image)
- [The part is not found when it is rotated or at a different distance](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#faq-rotation-scale)
- [A wide search reports weak matches in the wrong places](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#faq-spurious-matches)
- [`output/result` is empty although the search worked a moment ago](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#faq-result-empty)
- [The template file is on the device but missing from `system/templates`](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#faq-template-not-listed)
- [The image stream delivers no results](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#ts-stream-no-results)
- [My settings or modules are gone after a restart](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#faq-settings-lost)
- [The application stops shortly after starting](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#faq-app-stops-after-start)
- [Status code `-11` (licence unavailable)](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#ts-licence-unavailable)

## Licensing and support

### Which licence do I need, and how many modules does it cover? {#faq-licence}

- **Answer:** One licence covers ten modules; the eleventh module acquires a second licence of the same key, and a module is refused with status `-11` when no licence on the device covers it. Purchase routes:
  - Bought from HD Vision Systems: the licence is on a LumiScan Key (Windows 11 or Ubuntu 24.04). One LumiScan Key is needed per device running the software at the same time; keys can be exchanged between devices.
  - Bought in the ctrlX Store for Windows 11: ctrlX WORKS plus a LumiScan Key.
  - Bought in the ctrlX Store for ctrlX OS (ctrlX CORE or IPC): a ctrlX licence, no key.
- **More:** [Requirements](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/requirements.html#licence), [Module Management](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/module-management.html), [Licensing FAQ](https://docs.hdvisionsystems.com/en/lumiscan-licensing/1.0.4/faq.html)

### Where can I find more answers or get support? {#faq-support}

- **Answer:** See the site-wide [LumiScan FAQ](https://docs.hdvisionsystems.com/en/faq.html). Contact HD Vision Systems customer success at [customer.success@hdvisionsystems.com](mailto:customer.success@hdvisionsystems.com) or +49 6221 6721905; for licences, [licenses@hdvisionsystems.com](mailto:licenses@hdvisionsystems.com). Before reproducing a problem for a support report, set `logLevel` to `TRACE` in the `system` block of `lumiscan-template-finder.json` and restart the application.
- **More:** [Template Storage](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/template-storage.html), [Licensing FAQ](https://docs.hdvisionsystems.com/en/lumiscan-licensing/1.0.4/faq.html)

# Troubleshooting – LumiScan Template Finder

URL: https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html

This page describes problems and error messages of LumiScan Template Finder, grouped by category. Start with the [general checks](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#general-checks), then find your symptom below: each problem lists its symptoms, the possible causes, a diagnostic procedure and the resolution. Problems of the Data Layer itself are described in [Data Layer troubleshooting](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/troubleshooting.html), licence problems in [Licensing troubleshooting](https://docs.hdvisionsystems.com/en/lumiscan-licensing/1.0.4/troubleshooting.html).

## General checks {#general-checks}

1. **Check the status code.** Read `output/status-code` of the operation that failed. Expected: `1`. A value greater than 0 means success, `0` means the operation has not run since the application started, and a value less than 0 means it failed and produced nothing. The codes are listed in [Execution Status](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/execution-status.html).
2. **Read the status text.** Read `output/status-text` of the same operation. It starts with `ok:` or `error:` and names every invalid input and the value it holds. A failed write to `execute` answers with a status code only (over REST, a bare `400`), so the reason is only on `output/status-text`.
3. **Read the application log.** It holds the same text, with one warning line for each invalid input: on ctrlX OS in the ctrlX Logbook or with `journalctl`, on a PC in the application’s console output. How much is logged is set with `logLevel` in the `system` block of `lumiscan-template-finder.json` (`TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `FATAL` or `OFF`); without the key, the application logs at `DEBUG`. The level is read once, at startup, so restart the application after you change it. `TRACE` is what to set before you reproduce a problem for a support report. See [Template Storage](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/template-storage.html).
4. **Check the image source.** The camera application, normally LumiScan Cam Driver, must run on the **same device** - the same ctrlX CORE or ctrlX IPC, or the same PC - and must have captured an image. Remote Data Layer access is not supported. Expected: the node named in `input/input-image-address` provides `data`, `width`, `height` and `pixel-type`.
5. **Check the order of the calls.** A module runs one operation at a time, and every run clears its outputs as it starts. Expected: your program waits for `execute` to return, reads the outputs, and only then triggers the next run.
6. **Check the licence (ctrlX OS).** Expected: the application keeps running after it starts. Without a licence it shuts down shortly after starting; see [Problem: The application stops shortly after starting](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#faq-app-stops-after-start).

The configuration directory holds `lumiscan-template-finder.json`, the module files `<module-id>.json`, the `templates` folder and `settings-history/`:

| Platform | Configuration directory |
| --- | --- |
| ctrlX OS | `/var/snap/rexroth-solutions/common/solutions/activeConfiguration/lumiscan-template-finder`, part of the active solution |
| PC (Windows) | `%APP_RESOURCE_DIR%\etc\lumiscan-template-finder`; without `APP_RESOURCE_DIR`, `C:\ProgramData\HD Vision Systems GmbH\LumiScan Vision Suite\lumiscan-templ-find\etc\lumiscan-template-finder` |

## Status codes and error messages {#ts-status-codes}

### Problem: Status code `-1` (busy) {#faq-busy-while-streaming}

**Symptoms**

`output/status-code` of `find-template` is `-1`. The write to `execute` answers `TooManyOperations` (ctrlX: `DL_TOO_MANY_OPERATIONS`). Nothing was done, and `output/result` keeps its value. With a camera streaming, this happens often. `system/remove-module` can answer `-1` (busy) as well.

**Possible causes**

- Another operation of the same module was still running. A second call is not queued; it returns at once and does nothing.
- The module’s image stream is searching a frame. The stream and `find-template` never run at the same time on one module.

**Diagnostic procedure**

1. Check in your program whether it writes to `execute` of the same module again before the previous write has returned. Expected: one call per module at a time.
2. Read `<module-id>/control/subscribe/output/stream/active`. `true` means that the stream of this module runs.

**Resolution**

- **If another operation was still running:** wait for the running `execute` to return, then call the method again. The lock is per module, so other modules are not held up.

- **If the stream of the module runs:**

  a. Stop the stream before you call the method: set `control/subscribe/input/enable` to `false` and write to `control/subscribe/execute`. Or call the method again.

  b. To use the results of the stream instead, switch on `control/subscribe/input/keep-latest-output` and read `find-template/output/result`.

- **If `system/remove-module` answers busy:** stop the stream of the module first. Removing a module stops its stream.

See [Execute a Method](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/execute-a-method.html) and [find-template while the stream runs](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html#while-streaming).

**If the problem persists**

Send the information listed under [Information for support](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#support-information) to support, together with the module id, the answer of the write to `execute` and the value of `control/subscribe/output/stream/active`.

### Problem: Status code `-2` (invalid input) {#faq-status-minus-2}

**Symptoms**

`output/status-code` is `-2`. `output/status-text` starts with `error:` and names every offending input and the value it holds, for example `min-scale must be > 0, got 0`. Each one is also logged as a warning.

**Possible causes**

- A required input is empty: `input/input-image-address` or `input/template-name`.
- The match mode is misspelled. `input/match-mode` accepts `TM_SQDIFF`, `TM_SQDIFF_NORMED`, `TM_CCORR`, `TM_CCORR_NORMED`, `TM_CCOEFF` and `TM_CCOEFF_NORMED`.
- A search parameter is out of range, for example `input/scale/min-scale` or `input/rotation/step-rot` not greater than 0, or a rotation outside 0 to 360.
- The image address points at this application itself.
- A folder or file name is an absolute path, such as `/tmp/templates`, or a path that leads outside the configuration directory, such as `../../etc`.

**Diagnostic procedure**

1. Read `output/status-text` of the operation. Expected: it names each offending input and its value.
2. Read the application log. Each offending input is logged as a warning.

**Resolution**

- **If a required input is empty:** set it. `input/template-name` takes an entry of `system/templates`.
- **If the match mode is misspelled:** write one of the accepted names to `input/match-mode`.
- **If a search parameter is out of range:** correct it, see [Tuning the Search](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/tuning-the-search.html).
- **If the image address points at this application:** set `input/input-image-address` to the image node of the camera application, for example `hdvisionsystems/lumiscan-cam-driver/camera1/output/image`.
- **If a path is absolute or leaves the configuration directory:** give it relative to the configuration directory. A path that stays inside is fine even if it contains `..`.

Then run the operation again. Expected: `output/status-code` is `1`. See [Execution Status](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/execution-status.html) and [Template Storage](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/template-storage.html).

**If the problem persists**

Send the information listed under [Information for support](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#support-information) to support, together with the content of `output/status-text`.

### Problem: Status code `-3` (image read failed) {#faq-status-minus-3}

**Symptoms**

`output/status-code` of `find-template` or `system/create-template` is `-3`.

**Possible causes**

- The camera application is not running, or it runs on another device.
- The camera application has not captured an image yet.
- The address in `input/input-image-address` is wrong.
- The image node at the address is missing, empty or inconsistent.
- The image uses an unsupported pixel format. Supported are `Mono8`, `Mono12`, `RGB8`, `RGB12`, `BGR8`, `BGR12`, `BayerGR8`, `BayerGR12`, `BayerRG8` and `BayerRG12`.

**Diagnostic procedure**

1. Check that the camera application, normally LumiScan Cam Driver, runs on the same device. Expected: it runs on the same ctrlX CORE or ctrlX IPC, or on the same PC.
2. Compare `input/input-image-address` with the address of the camera’s image node, for example `hdvisionsystems/lumiscan-cam-driver/camera1/output/image`. Expected: identical. `system/create-template` and `find-template` each have their own address node.
3. Read `width`, `height` and `pixel-type` of the image node. Expected: values greater than 0, and a `pixel-type` from the list above.

**Resolution**

- **If the camera application is not running:** start it on the same device and capture an image.
- **If no image has been captured yet:** capture an image in the camera application.
- **If the address is wrong:** correct `input/input-image-address`.
- **If the pixel format is not supported:** use one of the supported pixel formats, see [Requirements](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/requirements.html).

Then run the operation again. Expected: `output/status-code` is `1`.

**If the problem persists**

Send the information listed under [Information for support](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#support-information) to support, together with the content of `output/status-text`, the image address and the `pixel-type` of the image node.

### Problem: Status code `-4` (source not found) {#faq-status-minus-4}

**Symptoms**

`output/status-code` of `find-template` is `-4`. `output/status-text` names a directory or a file.

**Possible causes**

- The message names a directory: the template folder does not exist. The default `templates` is created at startup, so either it was deleted or the folder name is wrong.
- The message names a file: the folder exists but holds no such file.
- The file is there but is not found: it is in a different folder from the one in use. All modules share one template folder.

**Diagnostic procedure**

1. Read `output/status-text`. Expected: it names a directory or a file.
2. Compare `input/template-name` with `system/templates`. Expected: the name is listed, spelled the same way.
3. Read `system/template-dir`. Expected: it names the folder that holds the file.

**Resolution**

- **If the folder does not exist:** switch to an existing folder with `system/set-template-dir`, or correct its name. The folder must already exist; it is not created for you.
- **If the folder holds no such file:** correct the spelling of `input/template-name`, or create the template with `system/create-template`.
- **If the file is in another folder:** move the file into the folder `system/template-dir` names, or switch with `system/set-template-dir`.

Then run `find-template` again. Expected: `output/status-code` is `1`. See [Template Storage](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/template-storage.html).

**If the problem persists**

Send the information listed under [Information for support](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#support-information) to support, together with the content of `output/status-text`, `input/template-name`, `system/template-dir` and `system/templates`.

### Problem: The crop region does not fit the image {#ts-crop-does-not-fit}

**Symptoms**

`system/create-template` answers status `-5` (invalid crop region), and `output/status-text` names the actual image size. For `find-template`, `output/status-text` names the input and the limit it broke, for example:

```
crop/startX + crop/width (100 + 541 = 641) exceeds the image width 640
```

In the image stream, the frame fails, and `control/subscribe/output/stream/last-failure` names a crop region that does not fit the frame.

**Possible causes**

- The region reaches past an edge of the image. A region reaching past an edge is refused, not trimmed.
- For `find-template`, the region is smaller than the template. This is refused with status `-5`.
- For `system/create-template`, `input/crop/width` or `input/crop/height` is 0. Both must be greater than 0.

**Diagnostic procedure**

1. Read the image size from the message, or `width` and `height` of the image node.
2. Add `input/crop/startX` and `input/crop/width`, and `input/crop/startY` and `input/crop/height`. Expected: the sums are not larger than the image width and the image height.
3. For `find-template`, compare the region with the size of the template. Expected: the region is at least as large as the template.

**Resolution**

- **If the region reaches past an edge:** correct `input/crop/startX`, `startY`, `width` or `height`, so that the region fits the image. A zero width or height reaches the right or bottom edge.
- **If the region is smaller than the template:** widen the region.
- **If width or height is 0 (`create-template`):** set both to the size of the region, greater than 0.

Then run the operation again. Expected: `output/status-code` is `1`. See [Finding a Template](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/finding-a-template.html) and [Creating a Template](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/creating-a-template.html).

**If the problem persists**

Send the information listed under [Information for support](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#support-information) to support, together with the content of `output/status-text` and the four `input/crop/` values.

### Problem: Status code `-6` (write failed) {#ts-status-minus-6}

**Symptoms**

`output/status-code` of `system/save-module-inputs` or `system/create-template` is `-6`.

**Possible causes**

- A file could not be written - usually a permission problem or a full disk.
- The configuration directory is not writable. The same problem is reported in the log at startup.

**Diagnostic procedure**

1. Read `output/status-text` of the operation. Expected: it names the file that could not be written.
2. Read the application log of the start. Expected: no message that the configuration directory is not writable.
3. Check the configuration directory (see [General checks](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#general-checks)). Expected: it exists and the application can write to it.

**Resolution**

- **If the configuration directory is not writable:** make it writable for the application.
- **If the disk is full:** free disk space on the device.

Then run the operation again. Expected: `output/status-code` is `1`.

**If the problem persists**

Send the information listed under [Information for support](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#support-information) to support, together with the content of `output/status-text` and the log of the start.

## Search results {#ts-results}

### Problem: The result is empty although the status code is `1` {#ts-empty-result}

**Symptoms**

`output/status-code` of `find-template` is `1`, but `matches` in `output/result` is empty, and `best_score` is `0.0`.

**Possible causes**

An empty `matches` list with status code `1` means that the search ran correctly and found nothing. That is a normal result: the part is not there, or not similar enough to pass the threshold. If a part that is there is not found:

- The template was cut from the wrong region or the wrong image, see [Problem: The template is not found even in the image it was cut from](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#faq-not-found-in-own-image).
- The part is rotated or at another distance than in the template, see [Problem: The part is not found when it is rotated or at a different distance](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#faq-rotation-scale).
- `input/crop` excludes the part.
- The template touches the edge of the image. Such a template cannot be found near the opposite edge, because the template must fit entirely inside the searched image.
- Background that changes from part to part is inside the template; it lowers every score.

**Diagnostic procedure**

1. Read `output/status-code`. Expected: `1`. If it is negative, the run failed: read `output/status-text` and see the entries under [Status codes and error messages](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#ts-status-codes).
2. Search the image the template was cut from. Expected: one match at the centre of the region you specified, with a confidence close to 1.
3. Compare the orientation and the size of the part in the image with the template.
4. Read the four `input/crop/` values. Expected: all `0` (the whole image), or a region that contains the part.
5. Read `match_thresh` in `output/result`: the threshold that was applied (default `0.9`).

**Resolution**

- **If the template is not found in its own image:** follow [Problem: The template is not found even in the image it was cut from](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#faq-not-found-in-own-image).
- **If the part is rotated or at another distance:** follow [Problem: The part is not found when it is rotated or at a different distance](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#faq-rotation-scale).
- **If the crop excludes the part:** widen the region, or set all four `input/crop/` values to `0`.
- **If the template touches the image border or holds changing background:** create the template again from a region that stays away from the image border, includes what identifies the part and excludes what varies. See [Creating a Template](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/creating-a-template.html).
- **If the part was not in the image:** the result is correct; nothing needs to be changed.

**If the problem persists**

Send the information listed under [Information for support](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#support-information) to support, together with `input/template-name`, the template file and `output/result`.

### Problem: The template is not found even in the image it was cut from {#faq-not-found-in-own-image}

**Symptoms**

A search in the very image the template was cut from does not report the match at the centre of the region you specified, with a confidence close to 1.

**Possible causes**

- The region given when the template was created is wrong.
- The image address is wrong: the template was cut from another image than the one searched. `system/create-template/input/input-image-address` and `<module>/find-template/input/input-image-address` are separate nodes.

The search parameters are not the cause, and no amount of tuning fixes it.

**Diagnostic procedure**

1. Compare `system/create-template/input/input-image-address` with `<module>/find-template/input/input-image-address`. Expected: the same image node.
2. Read the four `system/create-template/input/crop/` values. Expected: a region that contains the part in that image.
3. Read `system/create-template/output/template-path`. Expected: the file you search for, for example `templates/screw.png`.

**Resolution**

- Correct `input/input-image-address` and the crop region, then create the template again. Searched in the same image, it must be found exactly at the centre of the region you specified - (195, 250) for a region starting at (100, 200) that is 190 x 100 pixels - with a confidence close to 1.

See [Creating a Template](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/creating-a-template.html) and [How To: Match a Part from a Camera Image](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/how-tos/match-a-part-from-a-camera-image.html).

**If the problem persists**

Send the information listed under [Information for support](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#support-information) to support, together with the inputs of `system/create-template`, the template file and `output/result`.

### Problem: The part is not found when it is rotated or at a different distance {#faq-rotation-scale}

**Symptoms**

The template is found in the image it was cut from, but not in a new image in which the part is rotated or closer to or further from the camera.

**Possible causes**

- The defaults search the template at its original size and orientation only.

**Diagnostic procedure**

1. Read `input/rotation/min-rot`, `max-rot` and `input/scale/min-scale`, `max-scale` of the module. At the defaults (`0.0`, `0.0`, `1.0`, `1.0`) only the original orientation and size are searched.
2. Compare the part in the new image with the template. Expected: you know whether it varies in orientation, in size, or in both.

**Resolution**

Widen only what varies, one range at a time, and stop as soon as the part is found reliably:

- **If the part rotates:** set `input/rotation/max-rot` (for example `360`) with a coarse `input/rotation/step-rot` (for example `5`).
- **If the part changes distance:** set `input/scale/min-scale`, `input/scale/max-scale` and `input/scale/step-scale` (for example `0.9`, `1.1`, `0.05`).

Each scale/rotation combination is a separate pass over the image, so 72 rotations and 5 scales are 360 passes. If a wider range starts producing matches in the wrong places, see [Problem: A wide search reports weak matches in the wrong places](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#faq-spurious-matches). See [Tuning the Search](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/tuning-the-search.html).

**If the problem persists**

Send the information listed under [Information for support](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#support-information) to support, together with the scale and rotation inputs and `output/result`.

### Problem: A wide search reports weak matches in the wrong places {#faq-spurious-matches}

**Symptoms**

With a scale or rotation range, `matches` holds the real match and, beside it, matches at unrelated places.

**Possible causes**

- The confidence is not an absolute measure. The score map is rescaled for every scale/rotation step, so the best location of every step reaches a confidence near 1, and `input/match-thresh` acts per step. Only repeats at the same location are removed, so a weak match somewhere else can still appear.

**Diagnostic procedure**

1. Read `matches[0]` and `best_score`. Expected: the real match is the highest-confidence entry, at index 0.
2. Read the scale and rotation inputs. A single-scale, single-rotation search behaves as expected; a range can report spurious matches.

**Resolution**

- Raise `input/match-thresh`, for example to `0.95`, or narrow the scale and rotation range.

See [Tuning the Search](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/tuning-the-search.html).

**If the problem persists**

Send the information listed under [Information for support](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#support-information) to support, together with the inputs of `find-template` and `output/result`.

### Problem: `output/result` is empty although the search worked a moment ago {#faq-result-empty}

**Symptoms**

A run produced matches, and shortly afterwards `output/result` is empty.

**Possible causes**

- The next run has started. Every run clears its own outputs as soon as it begins, before anything that can fail. Triggering `execute` again and then reading gives the new run - possibly failed or still empty - not the previous one.
- A call refused with `-1` (busy) clears nothing, so this is not the cause when the second call was refused.

**Diagnostic procedure**

1. Check the order of the calls in your program. Expected: it reads `output/result` before it triggers the next `execute`.
2. Read `output/status-code` of the latest run. A negative value means that this run failed and left `output/result` empty.

**Resolution**

- **If the next run started too early:** wait for `execute` to return, read the outputs, and only then trigger the next run.
- **If the latest run failed:** follow the entry for its status code.

See [Execute a Method](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/execute-a-method.html).

**If the problem persists**

Send the information listed under [Information for support](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#support-information) to support, together with the sequence of calls your program makes.

## Templates {#ts-templates}

### Problem: The template file is on the device but missing from `system/templates` {#faq-template-not-listed}

**Symptoms**

A `.png` file is in the template folder, but `system/templates` does not list it.

**Possible causes**

- The file arrived by other means - an upload through the ctrlX web interface on ctrlX OS, or a file copied into the folder on a PC - and the list was not refreshed. The list is refreshed at startup, when `system/set-template-dir` succeeds and when `system/create-template` saves a template.
- The extension is not a lower case `.png`. `SCREW.PNG` is ignored.
- The file is in a different folder from the one in use.

**Diagnostic procedure**

1. Read `system/template-dir`. Expected: it names the folder that holds the file.
2. Check the file name. Expected: it ends in a lower case `.png`.

**Resolution**

- **If the extension is not a lower case `.png`:** rename the file to a lower case `.png`.
- **If the list was not refreshed:** execute `system/set-template-dir` again, naming the same folder. Expected: its status code is `1`, and `system/templates` lists the template.

A template added while the application runs can be searched for straight away: the file is read each time, not cached at startup. See [Template Storage](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/template-storage.html).

**If the problem persists**

Send the information listed under [Information for support](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#support-information) to support, together with `system/template-dir`, `system/templates` and the file name.

## Image stream (experimental) {#ts-stream}

### Problem: The image stream delivers no results {#ts-stream-no-results}

**Symptoms**

`control/subscribe/output/stream/active` stays `false`, no results arrive on `control/subscribe/output/stream/result`, or `control/subscribe/output/stream/statistics/failed-frames` grows.

**Possible causes**

- Only the inputs were written. Writing `control/subscribe/input/enable` alone starts nothing; `control/subscribe/execute` applies the inputs.
- `control/subscribe/execute` was refused (`Rejected`, ctrlX: `DL_INVALID_VALUE`): stream mode without an address, or a queue size outside `1` to `64`.
- The settings file `<module-id>.json` could not be written, for example because it is not valid JSON (`CreationFailed`, ctrlX: `DL_CREATION_FAILED`). Nothing changed.
- The stream of the Cam Driver does not run, so no frames arrive.
- The source cannot be subscribed to. The module tries it again every 5 seconds while the stream runs, and logs the first failure.
- Frames cannot be searched, for the reasons `find-template` gives in its `status-text`.

**Diagnostic procedure**

1. Read `hdvisionsystems/lumiscan-cam-driver/<camera name>/control/publish/output/stream/active`. Expected: `true`.
2. Read `setting/stream/enable` and `setting/stream/address` of the module. Expected: `true` and the camera’s stream folder, for example `hdvisionsystems/lumiscan-cam-driver/camera1/control/publish/output/stream`. They show what was applied last.
3. Check the answer of the write to `control/subscribe/execute`. Expected: `Ok` (ctrlX: `DL_OK`). These methods have no `status-text`; the reason for a refusal is in the application log.
4. Read `control/subscribe/output/stream/active`. Expected: `true`.
5. Read `received-frames`, `processed-frames` and `failed-frames` under `control/subscribe/output/stream/statistics/`. The first counter that does not grow shows where the chain stops.
6. If `failed-frames` grows, read `control/subscribe/output/stream/last-failure`. It says why the last frame failed, for example:
   ```
   a frame of 'hdvisionsystems/lumiscan-cam-driver/camera1/control/publish/output/stream' failed: invalid input: template-name is empty
   ```

**Resolution**

- **If only the inputs were written:** set `control/subscribe/input/enable` to `true` and write to `control/subscribe/execute`. Wait until `control/subscribe/output/stream/active` is `true`.
- **If the call was refused (`Rejected`, `DL_INVALID_VALUE`):** write the camera’s stream folder to `control/subscribe/input/address`, set `control/subscribe/input/queue-size` to a value from `1` to `64`, and write to `control/subscribe/execute` again.
- **If the settings file could not be written (`CreationFailed`, `DL_CREATION_FAILED`):** make `<module-id>.json` in the configuration directory valid JSON again, without comments, then write to `control/subscribe/execute` again.
- **If the stream of the Cam Driver does not run:** start it. It is not kept after a restart: call its `control/publish/execute` with `enable` = `true` after every start, and connect the camera first. See [A stream delivers nothing](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/troubleshooting.html#stream-nothing).
- **If the source cannot be subscribed to:** check that `control/subscribe/input/address` is the camera’s stream folder and that the Cam Driver runs on the same device.
- **If frames fail:** correct the input that `last-failure` names, as for a single `find-template` call.

See [Finding Templates on an Image Stream (Experimental)](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html).

**If the problem persists**

Send the information listed under [Information for support](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#support-information) to support, together with the values under `setting/stream/`, the counters under `control/subscribe/output/stream/statistics/`, `control/subscribe/output/stream/last-failure` and the module’s `<module-id>.json`.

## Modules, settings and licensing {#ts-modules}

### Problem: My settings or modules are gone after a restart {#faq-settings-lost}

**Symptoms**

After a restart of the application, a module is missing from `system/modules`, or a module’s inputs are back at their defaults.

**Possible causes**

- The module list was not saved. Settings and new modules are live at once but not permanent until saved; the module list and each module’s settings are saved separately.
- The module’s settings were not saved.
- A save failed: `system/save-module-inputs` or `system/save-current-modules` did not report status `1`.
- `<module-id>.json` contains comments. The stream reads such a file, but the module’s inputs are then not restored at start; the log reports the file as unreadable.
- A setting whose node no longer exists after a software update is skipped, with a log entry.

Results are not saved; they are produced by the next run. Template files are already permanent: they are files in the configuration directory, on ctrlX OS part of the active solution.

**Diagnostic procedure**

1. Read `system/modules` after the restart. Expected: all your modules.
2. Check the configuration directory (see [General checks](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#general-checks)). Expected: `lumiscan-template-finder.json` names your modules, and there is a `<module-id>.json` for each module whose settings you saved.
3. Read the application log of the start. Expected: no module file reported as unreadable, no skipped setting.

**Resolution**

- **If the settings or the module list were not saved:**

  a. Set `system/save-module-inputs/input/module-id` (for example `module-1`) and write to `system/save-module-inputs/execute`. Do this for each module.

  b. Write to `system/save-current-modules/execute`.

  c. Check that both report status `1`.

- **If the module file contains comments:** remove them from `<module-id>.json`. Changes made to the file by hand take effect at the next start.

- **If a setting was skipped after an update:** set the input again and save the module’s settings.

A module’s image stream settings need no extra step: `control/subscribe/execute` saves them in `<module-id>.json` itself. To have the module itself back, save the module list as well. See [Module Management](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/module-management.html) and [Kept in the settings file](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/processing-an-image-stream.html#saving).

**If the problem persists**

Send the information listed under [Information for support](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#support-information) to support, together with `lumiscan-template-finder.json` and the module files `<module-id>.json`.

### Problem: The application stops shortly after starting {#faq-app-stops-after-start}

**Symptoms**

On ctrlX OS, the application shuts down shortly after it starts. Its nodes under `hdvisionsystems/lumiscan-template-finder` disappear from the Data Layer.

**Possible causes**

- The licence is missing. The reason is written to the system log.
- The application needs more licences than are installed. One licence covers ten modules, see [Problem: Status code `-11` (licence unavailable)](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#ts-licence-unavailable).

**Diagnostic procedure**

1. Open the ctrlX OS system log (ctrlX Logbook or `journalctl`). Expected: it names the reason and the missing licence.
2. Compare the licence with the ctrlX licence of LumiScan Template Finder, `SWL-W-XCx-TEMPLxFDxxHDVS-V1NN`. Expected: it is installed on the device on which the application runs.

**Resolution**

- **If the licence is missing:** install a valid licence on the device and start the application again. Expected: it keeps running, and its nodes are on the Data Layer.

See [Licence](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/requirements.html#licence) and [My ctrlX app stops shortly after starting](https://docs.hdvisionsystems.com/en/lumiscan-licensing/1.0.4/troubleshooting.html#faq-ctrlx-app-stops).

**If the problem persists**

Send the information listed under [Information for support](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#support-information) to support, together with the lines of the system log that name the licence. For licences, contact [licenses@hdvisionsystems.com](mailto:licenses@hdvisionsystems.com).

### Problem: Status code `-11` (licence unavailable) {#ts-licence-unavailable}

**Symptoms**

A module is refused with status code `-11`.

**Possible causes**

- No licence on the device covers the module. One licence covers ten modules; the eleventh module acquires a second licence of the same key.

**Diagnostic procedure**

1. Count the entries of `system/modules`. Expected: no more than ten modules for each licence on the device.
2. Read `output/status-text` of the operation that answered `-11`.

**Resolution**

- **If more modules exist than the licences cover:** remove the modules you do not need with `system/remove-module` and save the module list with `system/save-current-modules`, or obtain another licence.

See [Module Management](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/module-management.html).

**If the problem persists**

Send the information listed under [Information for support](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#support-information) to support, together with `system/modules`. For licences, contact [licenses@hdvisionsystems.com](mailto:licenses@hdvisionsystems.com).

## Information for support {#support-information}

If a problem persists, send this information to support:

- **Software version:** the version of LumiScan Template Finder you run. The files in `settings-history/` in the configuration directory record it as `software.version`.
- **Platform:** ctrlX OS (ctrlX CORE or ctrlX IPC) and its ctrlX OS version, or a PC with Windows 11 or Ubuntu 24.04. Also say where you bought the software: from HD Vision Systems or in the ctrlX Store.
- **Data Layer:** the ctrlX Data Layer (ctrlX OS) or LumiScan Keryx (PC). On a PC, also the Data Layer address the application uses.
- **Log:** the application log from the time of the error - on ctrlX OS from the ctrlX Logbook or `journalctl`, on a PC the application’s console output. Before you reproduce the problem, set `logLevel` to `TRACE` in the `system` block of `lumiscan-template-finder.json` and restart the application.
- **Time:** the date and time of the error.
- **Communication status:** `output/status-code` and `output/status-text` of the operation that failed, and the answer of the write to `execute` (for example `TooManyOperations` or `DL_TOO_MANY_OPERATIONS`).
- **Configuration files:** `lumiscan-template-finder.json`, the `<module-id>.json` of the module concerned, the template file and, for the image stream, the file in `settings-history/` that its settings hash names. Where they are is listed under [General checks](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html#general-checks).

Contact HD Vision Systems customer success at [customer.success@hdvisionsystems.com](mailto:customer.success@hdvisionsystems.com) or +49 6221 6721905; for licences, [licenses@hdvisionsystems.com](mailto:licenses@hdvisionsystems.com). See also [Before you contact support](https://docs.hdvisionsystems.com/en/faq.html#faq-before-contacting-support) in the LumiScan FAQ.

# v1.1.0 - 2026.08.07 – LumiScan Template Finder

URL: https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/release-notes/v1-1-0-2026-08-07.html

First functioning release of LumiScan Template Finder. Earlier versions registered the application’s Data Layer nodes but returned a fixed placeholder result, so nothing in this list was usable before.

**Added:**

- **Template matching.** `<module>/find-template/execute` searches a camera image for a stored template and reports every occurrence it finds, with an oriented bounding box, a confidence, and the scale and rotation the match was found at. The search covers a configurable range of scales and rotations. See [Finding a Template](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/finding-a-template.html).
- **Template creation from a live image.** `system/create-template/execute` cuts a rectangular region out of a camera image and saves it as a template PNG, so a template can be produced from the real camera without transferring files. It is an application-wide operation: the template it writes is usable by every module at once. See [Creating a Template](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/creating-a-template.html).
- **Results as a flatbuffer.** `<module>/find-template/output/result` carries the matches together with the template name, the matching mode and the threshold that produced them, so a stored result can be interpreted later without knowing how the search was configured.
- **Several modules.** Each configuration lives under `<module-id>/` with its own settings and results, and modules can be created and removed while the application runs through `system/create-module` and `system/remove-module`. `system/save-current-modules` keeps the set across a restart, and `system/save-module-inputs` keeps one module’s settings. **One licence is valid for ten modules**; the eleventh acquires a second licence of the same key, and a module is refused with status `-11` when no licence covers it. See [Module Management](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/module-management.html).
- **One template directory for the whole application.** `system/template-dir` names the directory every module reads templates from and `create-template` writes them to, so a template only ever has to be created once. Change it with `system/set-template-dir`; the choice is saved and restored on the next start. A directory that does not exist is refused rather than created, so a typo is reported instead of silently producing an empty folder.
- **A list of the available templates.** `system/templates` reports what is in that directory, without the `.png` extension, so an entry can be pasted straight into `<module>/find-template/input/template-name` instead of a file name being guessed. It is refreshed at startup, when the directory changes, and when `create-template` saves a template. See [Template Storage](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/template-storage.html).
- **Search only part of the image.** `<module>/find-template/input/crop/` limits the search to a rectangle. A zero width or height reaches the corresponding edge, so the default all-zero region searches the whole image. A region reaching past an edge is refused, naming the input and the limit it broke, rather than being trimmed to fit.
- **Choose the frame the positions are reported in.** `<module>/find-template/input/result-coordinate` is `IMAGE` (the default) for positions in the full image, or `CROP` for positions inside the searched region.
- **The search range is grouped.** The scale, rotation and preprocessing inputs sit in folders of their own - `<module>/find-template/input/scale/`, `.../rotation/` and `.../preprocess/` - so a Data Layer browser shows three small groups instead of one flat list of fourteen values.
- **Status reporting on every operation.** Each operation reports `output/status-code` and `output/status-text`. The status code is signed, and the sign alone says whether the operation worked: negative is an error, zero means it has not run yet. See [Execution Status](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/execution-status.html).
- **Template storage in the active solution.** Templates are PNG files in the application’s configuration directory, so they are included when the solution is exported and restored with it on another device. The directory is created on first start, so there is somewhere to upload to on a new installation. See [Template Storage](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/template-storage.html).
- **A configurable log level.** `system/logLevel` in `lumiscan-template-finder.json` sets how much the application logs - `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `FATAL` or `OFF` - in the same block the other LumiScan applications use, so `TRACE` can be turned on for a support report and turned off again afterwards. It is read at startup, and a missing or misspelled value leaves the application as talkative as it was. See [Template Storage](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/template-storage.html).

**Notes:**

- Every method clears its own output nodes as it begins, before anything that can fail, so a failed run leaves them empty rather than holding what an earlier run produced. Status `-1` (busy) is the exception: that call never ran, so it leaves the running operation’s outputs alone. The outputs therefore belong to the run that is starting - read them before triggering the next one. See [Execute a Method](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/execute-a-method.html).
- `system/template-dir` and `system/templates` are read-only. The directory is changed only through `system/set-template-dir`, so the listing can never disagree with the directory it came from.
- Only files ending in a lower case `.png` are listed on `system/templates`, so give `create-template` a lower case name. A file copied into the directory by other means is usable at once but does not appear in the list until it is refreshed.
- Duplicate matches are removed before the result is published. Searching a range of scales or rotations finds the same part once per step, so without this a single part would be reported many times.
- The match confidence is rescaled for each scale/rotation step, so it is not an absolute measure of similarity, and the threshold applies per step rather than globally. This matters only when a range is searched; it is explained in [Tuning the Search](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/tuning-the-search.html).
- Directory and file names are always interpreted relative to the configuration directory. Absolute paths, and paths leading outside that directory, are rejected.

# LumiScan Template Finder

URL: https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/index.html

|   |   |   |
| --- | --- | --- |
| ![A screw cut out of the camera image as the template "screw"](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/_images/intro/step-1.svg)<br><br>**Cut a template from the image.** A small picture of the part, taken from the live camera image. | ![Two screws found, one of them rotated](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/_images/intro/step-2.svg)<br><br>**Find it, turned or scaled.** The part is found within the rotation and scale range you set. | Example result<br><br><br><br><br><br><br>Center<br>195, 250 px<br><br><br>Confidence<br>0.98<br><br><br>Scale<br>1.05<br><br><br>Rotation<br>35°<br><br>**Hand the result to your PLC.** Position, confidence, scale and rotation of each match. |

LumiScan Template Finder locates a known part in a camera image from a small picture of it, the template, and reports where the part is, how confident the match is, and the scale and rotation it was found at. Templates are cut straight from the live camera image, with no file transfer or image editor. Typical uses are presence checks, position feedback for a robot pick and orientation checks before an assembly step, on ctrlX OS or a Windows or Ubuntu PC.

LumiScan Template Finder runs on ctrlX OS (ctrlX CORE or ctrlX IPC) with the ctrlX Data Layer, and on a PC (Windows 11 or Ubuntu 24.04) with LumiScan Keryx. This manual covers both; where they differ, it says so.

For licensing, see [Licence](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/lumiscan-template-finder/requirements.html#licence). Questions? See the [FAQ](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/faq.html). A problem or an error message? See [Troubleshooting](https://docs.hdvisionsystems.com/en/lumiscan-template-finder/1.1.0/troubleshooting.html).
