# LumiScan Object Finder 1.1.0.7 – complete documentation

> All pages of the LumiScan Object 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-object-finder/1.1.0/

# Description – LumiScan Object Finder

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

LumiScan Object Finder locates known objects inside a camera image by their **shape**. You describe an object with one or more small pictures of it - its **templates** - and the application reports where that object appears in a larger image, how well it matched, and which of your pictures it matched.

Typical uses are presence and count checks, position feedback for a robot pick, sorting mixed parts on a belt, 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-object-finder/1.1.0/lumiscan-object-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 Object Finder; its own nodes are listed in the [Data Layer Reference](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/datalayer-reference.html).

## How it recognises an object

Matching is done on the **outline** of the object - the direction in which brightness changes across its edges - rather than on the brightness values themselves. That has two practical consequences.

It is **tolerant of lighting and surface finish**. A part that is shiny in one cell and matte in another, or lit from a different angle, still presents the same outline. Intensity based matching struggles here.

It is **not tolerant of rotation and size by itself**. The application does not turn or rescale your template looking for a fit. Instead, an object is described by **several templates** - one per orientation or working distance you want to recognise. Four templates recognise four orientations.

> [!NOTE]
> This is the main difference from **LumiScan Template Finder**, which correlates brightness and does search a range of scales and rotations, reporting an oriented box. Object Finder is faster and far more robust to lighting, and reports an axis-aligned rectangle plus the name of the object found. Choose Object Finder when lighting or finish varies and the orientations are known; choose Template Finder when the angle is continuous and unknown.

## 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 another view of an object. This is how you teach an object from the real camera, in the real lighting, at the real working distance - no file transfer and no image editor needed. See [Creating an Object](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/creating-an-object.html).

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

Both 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 Objects on an Image Stream (Experimental)](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/processing-an-image-stream.html).

## Where the images come from

The application does not talk to a camera itself. It reads an image node published by another application on the Data Layer, given as an address, for example:

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

The node must publish `data`, `width`, `height` and `pixel-type`, which is what LumiScan Cam Driver provides.

## Objects and modules

An **object** is something you want to find - a screw, a bracket - described by its templates. Objects belong to the whole application, so an object taught once can be found by every module.

A **module** is one configured instance of the search: its own camera address, its own settings and its own results, at its own Data Layer address. One installation can run several modules to watch several cameras at once. On ctrlX OS, one licence covers ten modules. See [Module Management](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/module-management.html).

# Requirements – LumiScan Object Finder

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

## Licence {#licence}

How LumiScan Object 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-OBJECTxFDxHDVS-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 Object 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 [Object Storage](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/object-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 Objects on an Image Stream (Experimental)](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-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-object-finder/1.1.0/lumiscan-object-finder/tuning-the-search.html).

# Execute a Method – LumiScan Object Finder

URL: https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-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-object-finder/1.1.0/lumiscan-object-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-object` 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-object` its `output/result`, `create-object` its `output/object-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 Object Finder

URL: https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-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 object directory or the object’s picture is missing or unreadable. Check the name against `system/objects` |
| `-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-object-finder/1.1.0/lumiscan-object-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 an object | `1`, `-1`, `-2`, `-3`, `-4`, `-7`, `-8` |
| Creating an object | `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 an Object – LumiScan Object Finder

URL: https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/creating-an-object.html

`system/create-object` cuts a rectangle out of a live camera image and saves it as an object. It is how you teach an object from the real camera, in the real lighting, at the real working distance.

It is an **application-wide** operation, not a per-module one: it writes into the one object directory every module shares, so an object taught once is findable by every module.

## Inputs

| Node | Meaning |
| --- | --- |
| `input/input-image-address` | Address of the image node to cut from. |
| `input/object-id` | The object’s name. Becomes `<object-id>.png` and appears on `system/objects`. An existing object of that name is **overwritten**. |
| `input/crop/startX`, `startY` | Top left corner of the region to cut. |
| `input/crop/width`, `height` | Size of the region. Both must be greater than 0. |

## Teaching an object

1. Put the part in front of the camera in the orientation it actually arrives in.
2. Set `object-id` to the object’s name.
3. Set the crop around the part and write to `execute`.

```
system/create-object/input/input-image-address = hdvisionsystems/lumiscan-cam-driver/camera1/output/image
system/create-object/input/object-id           = screw-m6
system/create-object/input/crop/startX         = 820
system/create-object/input/crop/startY         = 400
system/create-object/input/crop/width          = 160
system/create-object/input/crop/height         = 120
write system/create-object/execute
```

The picture is written to `<object-dir>/screw-m6.png` and `system/objects` picks it up straight away.

## Several orientations

The detector does not rotate the picture, so one object is one appearance. A part that arrives at more than one orientation needs **one object per orientation** - `screw-m6-front`, `screw-m6-tilted` - and a `find-object` run for each.

> [!TIP]
> **Start with the orientations the part really arrives in.** Each extra view costs a little matching time and buys tolerance to that one orientation - there is no value in views you will never see.

## How tight to crop

Leave **a few pixels of background** around the part - but only a few. Both directions cost you something, and the tight side is the one that fails quietly.

The detector keys on gradients, and an edge only exists where there is something different on the other side of it. Crop exactly along the part’s silhouette and there is nothing on the other side, so the outline produces **no features at all**. The detector blurs 7x7 and then runs a 3x3 Sobel, both replicating the edge pixel outward, so it discards the outermost ring of the picture and computes weakened gradients for about 4 pixels in from any edge.

> [!WARNING]
> A crop that stops at the silhouette hides the part’s outline from the detector. Either the object is **refused outright** - reported as a failed run naming it, because a template must yield a minimum number of strong gradient points - or it is accepted but keyed only on the part’s interior detail. The detector shrinks the template to the region where it found features, so it then matches on less than the picture shows, and a part that is distinctive mainly in outline matches poorly.

About **5 pixels of margin is enough** and more buys nothing. Background inside the template is background the detector then expects to see, so a loose crop that takes in a workbench edge or a neighbouring part makes matching less reliable. Aim for a thin, even band of the surface the part normally sits on.

On success `output/object-path` reports the file that was written, relative to the configuration directory, and `system/objects` is refreshed. Every module retrains before its next detection, so a new view is usable immediately.

## Failures

The whole crop must lie inside the image. A region that overflows is refused, naming the edge and the image size:

```
error: Crop region does not fit inside the 1920x1080 image: crop/startY + crop/height
(1000 + 200 = 1200) exceeds the image height 1080
```

`object-id` is interpreted relative to the configuration directory. An absolute path, or one climbing out with `..`, is refused with status `-2`.

`output/object-path` is emptied when a run starts, so a failed run never leaves a path pointing at a template it did not write. See [Execution Status](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/execution-status.html).

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

- [The crop region does not fit the image](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/troubleshooting.html#faq-crop-does-not-fit)
- [The run fails and names the object](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/troubleshooting.html#faq-object-refused-bin-size)
- [Status code `-2` (invalid input)](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/troubleshooting.html#ts-status-minus-2)

# Finding an Object – LumiScan Object Finder

URL: https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/finding-an-object.html

`<module>/find-object` searches one image, once, for a known object.

## Inputs

| Node | Default | Meaning |
| --- | --- | --- |
| `input/input-image-address` | (empty) | Address of the image node to search. |
| `input/object-id` | (empty) | Which object to look for. **Required** - an empty value is refused. |
| `input/confidence-threshold` | `0.6` | Smallest acceptable score, 0 to 1. |
| `input/nms-min-dist` | `0.0` | Minimum distance in pixels between two reported matches. |
| `input/pyramid` | `[1,2]` | Image pyramid levels the search runs at. Not a speed setting - see [Speed](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/tuning-the-search.html#speed). |
| `input/result-coordinate` | `IMAGE` | `IMAGE` or `CROP` - see below. |
| `input/crop/*` | all `0` | Region to search; all zero searches the whole image. |
| `input/preprocess/bin-size` | `1` | Search at a lower resolution: faster, less precise. See [Bin size](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/tuning-the-search.html#bin-size). |
| `input/preprocess/blur-*` | off | Optional blur - see [Tuning the Search](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/tuning-the-search.html). |

## Running it

Set the inputs, then write to `<module>/find-object/execute`:

```
module-1/find-object/input/input-image-address = hdvisionsystems/lumiscan-cam-driver/camera1/output/image
module-1/find-object/input/object-id           = screw-m6
module-1/find-object/input/confidence-threshold = 0.7
module-1/find-object/input/nms-min-dist         = 40
write module-1/find-object/execute
```

Then read `output/status-code` and `output/result`.

> [!TIP]
> Set `nms-min-dist` to roughly half the size of the part in pixels. Without it a single part is often reported several times over, as a cluster of slightly shifted matches.

## One object per search

`input/object-id` names one of the entries on `system/objects` and is **required**: an empty value is refused with status code `-2`.

There is no "search for everything" run. A detector is built around one picture, so searching several objects means several detectors, and each one re-processes the whole image - which is the expensive part. Running `find-object` once per object makes that cost visible rather than hiding it behind an empty input.

To sort mixed parts, run the method once per object and compare the scores.

## The result

`output/result` is an `object_find_result` flatbuffer.

| Field | Meaning |
| --- | --- |
| `matches[].x`, `.y` | Top left corner of the matched template, in pixels. |
| `matches[].width`, `.height` | Size of the template that matched, so the match can be drawn. |
| `matches[].score` | 0.0 to 1.0 similarity. |
| `matches[].object_id` | The object that was found; the same on every match of one run. |
| `best_index`, `best_score`, `best_object_id` | The highest scoring match. |
| `image_width`, `image_height` | The frame the coordinates are in. |
| `confidence_threshold` | The threshold that was applied. |
| `timestamp` | Microseconds since epoch, stamped when the run finished. |

Matches are sorted by score, so `matches[0]` is the best one.

There is no rotation in the result: the reported rectangle is axis aligned. If you need to know which orientation was found, give each orientation its own object - `screw-m6-front`, `screw-m6-tilted` - and search for them in turn. The answer is then the `object_id` that matched.

## Image and crop coordinates

`input/result-coordinate` chooses the frame positions are measured in:

- `IMAGE` (default) - the full image at `input-image-address`. This is what a robot pick needs.
- `CROP` - the searched region, whose top left corner becomes (0,0).

`image_width` and `image_height` follow the same choice, so normalising a coordinate by them is correct either way.

## The region is searched exactly as given {#multiple-of-16}

Any size works, and no part of `input/crop` is dropped. cv::linemod does need the image it is handed to be a particular multiple, but the detector **pads** up to it internally rather than demanding a size it likes, so nothing you configure has to satisfy a rule.

This used to trim instead, costing up to 7 pixels at the right and bottom edges - 31 at `bin-size` 4. Trimming was worse than it looked: it threw away columns the camera really captured, **and** left cv::linemod’s own dead border - it ignores the outer ring of whatever it is given - sitting on the pixels that survived. Measured, an object at the last usable position scored **0.79 trimmed against 1.00 padded**.

The padding replicates the edge pixels outward, so it introduces no gradients of its own and cannot be mistaken for a shape, and a match is never reported from inside it. It is added at the right and bottom only, so every reported position is still a position in the image you configured.

## What an empty result means

An empty result with `status-code` 1 means **the object was not in the image**, and nothing else.

Every other reason a search could come back empty - the object has no picture, the image is unusable, a pyramid level is invalid, `bin-size` left too little of the object to recognise - is detected before the search runs and reported as a negative status code. See [Execution Status](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/execution-status.html).

## Detection speed

The picture is compiled into a detector the first time it is used, and that detector is reused for as long as the settings and the object stay unchanged. Changing any input, or saving a new template, rebuilds it on the next run.

Compiling is by far the most expensive part of a run, so a production loop that executes repeatedly with unchanged settings pays that cost once. Changing a setting before every call pays it every time.

To make the search itself faster, narrow `input/crop` first and then raise `input/preprocess/bin-size`. Raising `input/pyramid` does **not** help - see [Speed](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/tuning-the-search.html#speed).

## Searching every frame of a camera

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

# Finding Objects on an Image Stream (Experimental) – LumiScan Object Finder

URL: https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-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-object` 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-object` as they are at that moment: the object, the confidence threshold, the crop region and every other node under `find-object/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-object-finder/1.1.0/lumiscan-object-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-object-finder/1.1.0/lumiscan-object-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 Object 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-object-finder/<module-id>/`. They sit beside `find-object/`, 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-object-finder/1.1.0/lumiscan-object-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-object-finder/1.1.0/lumiscan-object-finder/processing-an-image-stream.html#queue-size). |
| `control/subscribe/input/keep-latest-output` | bool | `true` to write each stream result to `find-object/output/result` as well. See [Keeping the latest output](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-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-object-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-object-finder/1.1.0/lumiscan-object-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-object-finder/1.1.0/lumiscan-object-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_object_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-object-finder/1.1.0/lumiscan-object-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-object-finder/1.1.0/lumiscan-object-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-object-finder/1.1.0/lumiscan-object-finder/processing-an-image-stream.html#statistics). |

The stream publishes its results on `control/subscribe/output/stream/result`. Of the nodes of `find-object` it writes only `find-object/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-object` as for a single search, see [Finding an Object](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/finding-an-object.html). A call of `find-object/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-object-finder/module-1/control/subscribe/input/address hdvisionsystems/lumiscan-cam-driver/camera1/control/publish/output/stream
krxclient write hdvisionsystems/lumiscan-object-finder/module-1/control/subscribe/input/enable true
krxclient execute hdvisionsystems/lumiscan-object-finder/module-1/control/subscribe/execute
krxclient subscribe hdvisionsystems/lumiscan-object-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-object-finder/1.1.0/lumiscan-object-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-object-finder/1.1.0/lumiscan-object-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_object_matches` (file identifier `HSOM`), registered on the Data Layer as `types/hdvisionsystems/lumiscan-object-finder/stream_object_matches`. Its compiled schema is installed as `bfbs/stream_object_matches.bfbs`.

| Field | Meaning |
| --- | --- |
| `lineage` | Where the result came from, see [The lineage of a result](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/processing-an-image-stream.html#lineage). |
| `result` | The matches, as a `hdv.object_find.Result`: the same table `find-object` writes to `output/result` for the same picture, described in [Finding an Object](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/finding-an-object.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-object` decodes the image node, so the same pixel formats are accepted, see [Requirements](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-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: object-id is empty - name the object to search for, see system/objects
```

The reasons are the ones `find-object` gives in its `status-text`: an input it would refuse, an object that is not listed on `system/objects` or has no picture, a crop region that does not fit the frame, a region the detector cannot search.

## 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-object-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-object-finder/1.1.0/lumiscan-object-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-object` the search reads, exactly as it was read for the frame - all of them but `input/input-image-address`;
- the object’s picture, by its content: a new picture saved under the old object id 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.

The stream compares the picture’s content with the picture the module’s detector was trained on, for every frame. When they differ, the detector is trained again before the frame is searched, so a result is never made with a picture its hash does not name. `find-object` on its own does not compare the content: it trains again when a detector setting changes or the object list is refreshed, see [Object Storage](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/object-storage.html).

`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-object/input/confidence-threshold": 0.6,
        "find-object/input/object-id": "screw-m6",
        "find-object/template": {
            "file": "<object directory>/screw-m6.png",
            "fnv1a64": "<16 hex digits>"
        },
        "software.name": "lumiscan-object-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-object-finder/1.1.0/lumiscan-object-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-object`. 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-object-finder` |
| PC (Windows) | `%APP_RESOURCE_DIR%\etc\lumiscan-object-finder`; without `APP_RESOURCE_DIR`, `C:\ProgramData\HD Vision Systems GmbH\LumiScan Vision Suite\lumiscan-obj-find\etc\lumiscan-object-finder` |

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

```json
{
    "find-object": {
        "object-id": "screw-m6"
    },
    "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-object/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-object-finder/1.1.0/lumiscan-object-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-object/output/result`, as `find-object/execute` writes it, once the result is published on `control/subscribe/output/stream/result`. A client that reads `find-object/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-object` left there. It costs a copy of each result. Off by default.

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

The stream and `find-object` use the same inputs and the module’s one trained detector, and they never run at the same time on one module:

- A frame that arrives while `find-object` runs waits until the method has finished. It is delayed, not failed.
- A call of `find-object/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-object-finder/1.1.0/lumiscan-object-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-object` 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 Object Finder

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

The defaults find a well-taught object in a reasonable image. This page is what to change when they do not.

## Confidence threshold

`input/confidence-threshold` is the smallest score a match must reach, from 0 to 1. It defaults to `0.6`.

Scores here are comparable between runs, so the practical method is to measure rather than guess:

1. Set the threshold low, to `0.4`.
2. Run against real parts, and look at the scores in `output/result`.
3. Set the threshold below the worst score a genuine part produces, with a little margin.

A threshold at or above `0.9` will usually reject everything, including good matches.

## Removing duplicate reports

`input/nms-min-dist` is the minimum distance in pixels between two reported matches. Where several matches fall within that distance, only the highest scoring one is kept.

Without it a single part is commonly reported several times, as a cluster of matches a few pixels apart. Set it to roughly **half the size of the part in pixels**. The default of `0` keeps every match, which is only useful when parts genuinely sit closer together than their own size.

## Blurring

`input/preprocess/blur-sigma-x` applies a Gaussian blur to both the image and the object’s picture before matching. It is **off by default**.

Turn it on - start at `1.0` - when scores hover near the threshold or the images are noisy. Measured on real fixtures, blurring lifts weak matches noticeably (roughly 0.53 to 0.60) while leaving already strong matches about where they were. That is exactly why it is off by default: it helps the borderline cases and does nothing for the healthy ones.

`blur-sigma-y` defaults to the same value as X. The kernel sizes are computed from the sigma unless you set them, in which case they must be odd. All of them are ignored while `blur-sigma-x` is 0 or less.

The blur is applied **before** binning, so a sigma stays a count of pixels in your original image and does not change meaning when you change `bin-size`.

## Bin size {#bin-size}

`input/preprocess/bin-size` downsamples both the image and the object’s picture by an integer factor before matching. It defaults to `1`, which disables it. **This is the setting that makes a search faster.**

The cost of a match scales with the pixel count, so binning pays off steeply. Measured on a 1920x1080 image with a 128x128 object, mean of five runs:

| `bin-size` | Time | Best score | Compared to 1 |
| --- | --- | --- | --- |
| `1` (default) | 49 ms | 1.00 | - |
| `2` | 8.4 ms | 1.00 | about 6x faster |
| `4` | 3.5 ms | 0.94 | about 14x faster |
| `8` | - | - | the object was refused - too small once binned |

What you give up is **precision** - reported positions quantise to `bin-size` pixels - and **detail**. Bin far enough and the object’s picture no longer has the edges the detector keys on: at `bin-size` 8 a 128x128 object is reduced to 16x16 and the detector refuses it. That is reported as a failed run naming the refused object, never as an empty result, so it cannot be mistaken for an absent part.

Positions in `output/result` are always in the pixels of the image you configured - the application scales them back - so raising `bin-size` changes nothing about how you read the result.

Small objects reach that limit sooner than large ones. Raise `bin-size` one step at a time and watch the scores: when they start dropping towards the threshold, you have gone one step too far.

`bin-size` costs you nothing at the edges of the region: it is searched exactly as configured whatever the bin - see [The region is searched exactly as given](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/finding-an-object.html#multiple-of-16).

## Pyramid levels

`input/pyramid` lists the image pyramid levels the search runs at, defaulting to `[1,2]`. Larger values make the detection more tolerant but coarser.

> [!NOTE]
> **This is not a speed setting**, although it reads like one. Deeper pyramids measured slightly *slower*, not faster - `[1,2]` 47 ms, `[2,4]` 50 ms, `[4,8]` 51 ms on the same image - because the detector’s per-level work grows about as fast as its per-pixel work shrinks. Use `bin-size` for speed and `pyramid` for tolerance.

Which levels are valid depends on the image size, and there is no general rule. An invalid combination is reported as a failed run with a negative status code rather than being guessed at, so change it in small steps and check the status.

## Restricting the area

`input/crop/{startX, startY, width, height}` restricts the search to part of the image. A zero width or height reaches the corresponding edge, so the default all-zero region searches everything and `startX=100` with zero sizes searches from there to the bottom right corner.

Two reasons to use it: speed, since a smaller region is searched faster, and reliability, since excluding areas where the part cannot be avoids false matches on similar-looking background.

This is the first thing to reach for when a search is too slow, because unlike `bin-size` it costs no precision at all.

The region is searched exactly as you set it - see [The region is searched exactly as given](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/finding-an-object.html#multiple-of-16).

## Adding views instead of tuning

If an object is missed at **particular orientations** while being found reliably at others, no setting here will fix it. The detector does not rotate templates - teach another view at the orientation being missed. See [Creating an Object](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/creating-an-object.html).

Likewise, if the object is missed when it sits closer to or further from the camera, teach a view at that distance.

## Speed {#speed}

The order of things to try:

1. **Restrict the area** with `input/crop`. This costs no precision, so it always comes first.
2. **Raise `input/preprocess/bin-size`**, at the cost of precision and of fine detail. On a full HD image this is worth roughly 6x at `2` and 14x at `4`.
3. **Search for fewer objects.** Each `execute` searches for one object and reprocesses the whole image, so dropping an object you do not need removes a whole run.

Raising `input/pyramid` is **not** on this list: measured, it is slightly slower rather than faster.

Keep the settings stable between runs. The detector is compiled from the object’s picture on the first run and reused while nothing changes; changing any input rebuilds it, and rebuilding costs far more than a detection.

# Object Storage – LumiScan Object Finder

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

## One file per object

An object **is** its picture: one `.png` at the top of the object directory, named after the object.

```
<configuration directory>/objects/
├── screw-m6.png
└── bracket.png
```

which the application publishes as

```
system/objects = ["bracket", "screw-m6"]
```

There is no second listing, because there is nothing else to list - the object id and the picture are the same thing. A detector is built around exactly one picture, so a second view of an object has nowhere to go: an object that has to be recognised at two orientations is two objects, `screw-m6-front` and `screw-m6-tilted`, searched for in turn.

Anything that is not a `.png` file at the top of the directory is skipped, subdirectories included.

Only lower case `.png` is listed. `.PNG` is ignored deliberately: matching case-insensitively would let `screw.png` and `screw.PNG` collapse into one entry, and the listing would no longer say which file a name refers to.

## Getting objects onto the device

Either teach them from the camera with [create-object](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/creating-an-object.html), or put `.png` files into the application’s configuration directory in the layout above: upload them on ctrlX OS, copy them in on a PC. The configuration directory and its default `objects` folder are created at startup, so there is somewhere to put them straight after installing.

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

## Changing the directory

`system/object-dir` names the directory in use. It is **read-only**, and `system/set-object-dir` is the only thing that changes it:

```
system/set-object-dir/input/object-dir = production-parts
write system/set-object-dir/execute
```

The method validates first and publishes `object-dir` and `objects` together, so a rejected call leaves both exactly as they were and the listings always describe the directory actually in use. The choice is saved, so it survives a restart.

The directory must already exist inside the configuration directory. It is deliberately not created for you: the default is created at startup, so a missing one means a typo, and silently creating an empty folder would hide it.

> [!NOTE]
> The Data Layer does not enforce read-only on an application’s own nodes, so a client that writes `system/object-dir` directly will change the value shown. It will **not** change which directory the application reads, and the listings will then describe a different folder than the node claims. Use `set-object-dir`.

## Path rules

`object-dir` and `object-id` are both interpreted relative to the configuration directory. Absolute paths, and any path climbing out with `..`, are refused with status `-2`. The application can therefore only read and write templates inside its own configuration area, whatever a client asks for.

## When changes are noticed

`system/objects` is refreshed at startup, when `set-object-dir` switches directory, and when `create-object` saves a template.

Files added or removed by other means - an upload or an SSH session on ctrlX OS, files copied in or deleted by hand on a PC - are picked up at the next one of those, or at the next restart. Each refresh also makes every module rebuild its detector, so a template removed from disk stops being findable.

# Module Management – LumiScan Object Finder

URL: https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-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-object-finder/<module-id>/find-object/...
```

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-object`. See [Creating an Object](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/creating-an-object.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-object-finder/system/
```

## Nodes

| Node | Type | Description |
| --- | --- | --- |
| `modules` | string array | The modules that currently exist |
| `create-object/execute` | method | Cut a template out of a live image and save it into `object-dir`, for every module to use. See [Creating an Object](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/creating-an-object.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-object-finder/1.1.0/lumiscan-object-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/object-dir` names one directory for the whole application, `system/create-object` writes into it, and every module searches it, so a template only ever has to be created once. See [Object Storage](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/object-storage.html).

# Data Layer Reference – LumiScan Object Finder

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

Every address below is relative to

```
hdvisionsystems/lumiscan-object-finder/
```

## Data Layer {#data-layer}

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

On ctrlX OS (ctrlX CORE or ctrlX IPC), LumiScan Object 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 Object 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 Object 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).

## Application-wide nodes

| Address | Type | Access | Description |
| --- | --- | --- | --- |
| `system/modules` | string[] | read | The modules that exist right now |
| `system/object-dir` | string | read | Directory object pictures are read from, relative to the configuration directory |
| `system/objects` | string[] | read | Objects that can be searched for, one per `.png` |
| `system/set-object-dir/execute` | method | write | Switch to another object directory |
| `system/set-object-dir/input/object-dir` | string | read/write | Directory to switch to |
| `system/create-object/execute` | method | write | Save a crop of a live image as an object |
| `system/create-object/input/input-image-address` | string | read/write | Image to cut from |
| `system/create-object/input/object-id` | string | read/write | The object’s name; also the file name. Overwrites an existing one |
| `system/create-object/input/crop/startX` | int32 | read/write | Left edge of the region to cut |
| `system/create-object/input/crop/startY` | int32 | read/write | Top edge |
| `system/create-object/input/crop/width` | int32 | read/write | Width, must be > 0 |
| `system/create-object/input/crop/height` | int32 | read/write | Height, must be > 0 |
| `system/create-object/output/object-path` | string | read | File written by the last run |
| `system/create-module/execute` | method | write | Add a module |
| `system/create-module/input/module-id` | string | read/write | Name for the new module |
| `system/remove-module/execute` | method | write | Remove a module |
| `system/remove-module/input/module-id` | string | read/write | Module to remove |
| `system/save-current-modules/execute` | method | write | Persist the module list |
| `system/save-module-inputs/execute` | method | write | Persist one module’s settings |
| `system/save-module-inputs/input/module-id` | string | read/write | Module to save |
| `system/meta/subscription-schema` | string | read | 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. Experimental |

Every method also serves `output/status-code` and `output/status-text`. On ctrlX OS, one licence covers ten modules, see [Module Management](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/module-management.html).

## Per-module nodes

All addresses below are under `<module-id>/find-object/`.

| Address | Type | Access | Default | Description |
| --- | --- | --- | --- | --- |
| `execute` | method | write | - | Run one detection |
| `input/input-image-address` | string | read/write | (empty) | Address of the image node to search |
| `input/object-id` | string | read/write | (empty) | Object to look for. **Required** - an empty value is refused |
| `input/confidence-threshold` | float64 | read/write | 0.6 | Smallest acceptable score, 0 to 1 |
| `input/nms-min-dist` | float64 | read/write | 0.0 | Minimum pixel distance between two matches |
| `input/pyramid` | uint8[] | read/write | [1,2] | Image pyramid levels to search at. Not a speed setting |
| `input/result-coordinate` | string | read/write | IMAGE | `IMAGE` or `CROP` |
| `input/crop/startX` | uint16 | read/write | 0 | Left edge of the region to search |
| `input/crop/startY` | uint16 | read/write | 0 | Top edge |
| `input/crop/width` | uint16 | read/write | 0 | Width; 0 reaches the right edge |
| `input/crop/height` | uint16 | read/write | 0 | Height; 0 reaches the bottom edge |
| `input/preprocess/bin-size` | int32 | read/write | 1 | Search at 1/N resolution: faster, less precise. 1 disables it |
| `input/preprocess/blur-sigma-x` | float64 | read/write | 0.0 | Gaussian blur in X; 0 or less disables it |
| `input/preprocess/blur-sigma-y` | float64 | read/write | 0.0 | Gaussian blur in Y; 0 means same as X |
| `input/preprocess/blur-kernel-size-x` | uint32 | read/write | 0 | Blur kernel in X; 0 computes it, else odd |
| `input/preprocess/blur-kernel-size-y` | uint32 | read/write | 0 | Blur kernel in Y; 0 computes it, else odd |
| `output/result` | flatbuffers | read | empty | Matches of the last run |
| `output/status-code` | int16 | read | 0 | Outcome as a number |
| `output/status-text` | string | read | (empty) | Outcome in words |

## Per-module image stream nodes (experimental)

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

| Address | Type | Access | Default | Description |
| --- | --- | --- | --- | --- |
| `control/subscribe/input/enable` | bool | read/write | as applied | Stream mode: `true` runs the stream, `false` stops it |
| `control/subscribe/input/address` | string | read/write | 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 | read/write | 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 | read/write | as applied | Frames that may wait while one is searched, 1-64 |
| `control/subscribe/input/keep-latest-output` | bool | read/write | as applied | `true` also writes each stream result to `find-object/output/result` |
| `control/subscribe/execute` | method | write | - | 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 | write | - | Drop the source named by `control/unsubscribe/input/address`, which ends stream mode; the tag stays. Saved in `<module-id>.json` like a subscribe |
| `control/unsubscribe/input/address` | string | read/write | (empty) | The source to drop, as `setting/stream/address` shows it |
| `setting/stream/{enable, address, tag, queue-size, keep-latest-output}` | as the inputs | read | `stream` in `<module-id>.json` | What `control/subscribe/execute` or `control/unsubscribe/execute` applied last |
| `setting/settings-hash` | string | read | - | Hash of what the results are made with, 16 hex digits |
| `control/subscribe/output/stream/active` | bool | read | false | `true` while the stream runs |
| `control/subscribe/output/stream/result` | flatbuffers | read | empty | One `stream_object_matches` per searched frame. Subscribe to receive each one |
| `control/subscribe/output/stream/last-failure` | string | read | (empty) | Why the last frame that could not be searched failed, naming the source by its address |
| `control/subscribe/output/stream/statistics/elapsed-ms` | uint64 | read | 0 | Milliseconds since the stream started |
| `control/subscribe/output/stream/statistics/received-frames` | uint64 | read | 0 | Frames the subscription delivered |
| `control/subscribe/output/stream/statistics/processed-frames` | uint64 | read | 0 | Frames searched, each with a result |
| `control/subscribe/output/stream/statistics/skipped-frames` | uint64 | read | 0 | Frames pushed out of the queue, or waiting when the source was replaced or dropped |
| `control/subscribe/output/stream/statistics/failed-frames` | uint64 | read | 0 | Frames that could not be searched |
| `control/subscribe/output/stream/statistics/lost-frames` | uint64 | read | 0 | Frames lost before they arrived |
| `control/subscribe/output/stream/statistics/processing-us` | uint64 | read | 0 | 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).

## The result flatbuffer

`output/result` carries `hdv.object_find.Result`:

| Field | Type | Meaning |
| --- | --- | --- |
| `matches` | Match[] | All matches, sorted by score descending |
| `matches[].x`, `.y` | int | Top left corner of the matched template, in pixels |
| `matches[].width`, `.height` | int | Size of the template that matched |
| `matches[].score` | float | 0.0 to 1.0 similarity |
| `matches[].object_id` | string | The object that was found; the same on every match of one run |
| `best_index` | ulong | Index of the best match; 0 when there are none |
| `best_score` | float | Score of the best match; 0.0 when there are none |
| `best_object_id` | string | Object of the best match; empty when there are none |
| `image_width`, `image_height` | uint | The frame the coordinates are in |
| `confidence_threshold` | float | The threshold that was applied |
| `timestamp` | ulong | Microseconds since epoch, when the run completed |

`control/subscribe/output/stream/result` carries `hdv.stream.StreamObjectMatches` (`stream_object_matches`, registered as `types/hdvisionsystems/lumiscan-object-finder/stream_object_matches`): `lineage`, where the frame came from, and `result`, the `hdv.object_find.Result` above.

## Configuration file

The application settings file `lumiscan-object-finder.json` is in the configuration directory:

| Platform | File |
| --- | --- |
| ctrlX OS | `<active solution>/lumiscan-object-finder/lumiscan-object-finder.json` |
| PC (Windows) | `%APP_RESOURCE_DIR%\etc\lumiscan-object-finder\lumiscan-object-finder.json`; without `APP_RESOURCE_DIR`, `C:\ProgramData\HD Vision Systems GmbH\LumiScan Vision Suite\lumiscan-obj-find\etc\lumiscan-object-finder\lumiscan-object-finder.json` |

```json
{
    "system": { "logLevel": "INFO" },
    "object-dir": "templates",
    "modules": [ { "id": "module-1", "advanced": false } ]
}
```

`logLevel` accepts `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `FATAL` and `OFF`, and is read at startup. Each module’s saved settings are in `<module-id>.json` beside it, and so are its image stream’s mode, source, queue size and keep-latest-output, under `stream`.

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

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

```shell
lumiscan-obj-find --generate-settings C:\work\object-finder-settings
```

Without a folder (`-g` alone) it writes into the current folder. The example is the application settings file `lumiscan-object-finder.json`, which names the module `module-1`, and the module file `module-1.json` beside it: every input of `find-object` 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-object-finder.schema.json`, `lumiscan-object-finder-module.schema.json`, and `stream.schema.json` for the `stream` section of a module file. They describe every key the Object Finder reads - each input of `find-object` 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 Object Finder says which.

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

# How To: Find a Part from a Camera Image – LumiScan Object Finder

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

Start to finish: teach a part from a live camera, find it, and make the settings survive a restart.

## Before you start

- LumiScan Cam Driver is installed on the same device and publishing an image, for example at `hdvisionsystems/lumiscan-cam-driver/camera1/output/image`.
- LumiScan Object Finder is installed - on ctrlX OS also licensed - and `system/modules` lists `module-1`.
- The part is in front of the camera, in the lighting the installation will actually use.

## Step 1: teach the first view

Look at the live image and note the pixel rectangle the part occupies - on ctrlX OS the ctrlX web interface shows the image - or read `width` and `height` from the image node.

Set the inputs and execute:

```
system/create-object/input/input-image-address = hdvisionsystems/lumiscan-cam-driver/camera1/output/image
system/create-object/input/object-id           = screw-m6
system/create-object/input/crop/startX         = 820
system/create-object/input/crop/startY         = 400
system/create-object/input/crop/width          = 160
system/create-object/input/crop/height         = 120
write system/create-object/execute
```

Check `system/create-object/output/status-code` is `1`, and `output/object-path` names the file. `system/objects` should now include `screw-m6`.

Crop tightly. Background inside the template is background the detector will expect to see.

## Step 2: teach the other orientations

The detector does not rotate a picture, so each orientation the part arrives in needs its own **object**. Repeat step 1 with a different `object-id` - `screw-m6-tilted`, say - and search for it in its own run.

If the part only ever arrives one way up, one object is enough.

## Step 3: find it

```
module-1/find-object/input/input-image-address = hdvisionsystems/lumiscan-cam-driver/camera1/output/image
module-1/find-object/input/object-id           = screw-m6
module-1/find-object/input/nms-min-dist        = 40
write module-1/find-object/execute
```

Read `module-1/find-object/output/status-code`. `1` means the run completed; then read `output/result`.

`nms-min-dist` at roughly half the part’s size in pixels stops one part being reported as a cluster of matches.

## Step 4: set the threshold from real parts

Run step 3 several times with real parts and note the `score` of the genuine matches. Then set

```
module-1/find-object/input/confidence-threshold = <a little below the worst genuine score>
```

If genuine scores hover near the threshold, turn on blurring - set `module-1/find-object/input/preprocess/blur-sigma-x` to `1.0` - and measure again. See [Tuning the Search](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/tuning-the-search.html).

## Step 5: make it permanent

Settings take effect immediately but are not saved until you ask:

```
system/save-module-inputs/input/module-id = module-1
write system/save-module-inputs/execute
write system/save-current-modules/execute
```

Both should report status `1`. The module and its settings now come back after a restart.

## Step 6: run it from a control program

Per cycle:

1. Write to `module-1/find-object/execute`.
2. Read `module-1/find-object/output/status-code`.
3. If it is negative, the run failed - read `output/status-text` for the reason and do not use the result.
4. If it is `1`, read `output/result`. An empty `matches` list means the part was not there.

Read the outputs **before** triggering the next `execute`: a run empties them as it starts.

To have every frame of the camera searched without a call per image, see [Finding Objects on an Image Stream (Experimental)](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/processing-an-image-stream.html).

## If the part is not found

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

- [The result is empty although the status code is `1`](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/troubleshooting.html#faq-empty-result) - scores just below the threshold, a part found in some orientations or at some working distances only, or never found at all
- [One part is reported several times](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/troubleshooting.html#faq-duplicate-matches)
- [Status codes and error messages](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/troubleshooting.html#ts-status-codes) - when `status-code` is negative

# FAQ – LumiScan Object Finder

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

Short answers to common questions about LumiScan Object 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-object-finder/1.1.0/troubleshooting.html).

## Requirements and setup

### On which platforms does the Object 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-object-finder/1.1.0/lumiscan-object-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 Object 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).
- **More:** [Requirements](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/requirements.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. Any other pixel format is rejected with status code `-3`.
- **More:** [Requirements](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/requirements.html)

## Teaching objects

### How do I teach an object from the live camera? {#faq-create-object}

- **Answer:** Use `system/create-object`, which is application-wide, so an object taught once is findable by every module:
  - Put the part in front of the camera, in the lighting the installation will use.
  - Set `system/create-object/input/input-image-address`, `input/object-id` (for example `screw-m6`) and `input/crop/startX`, `startY`, `width`, `height` (width and height greater than 0).
  - Write to `system/create-object/execute` and check that `output/status-code` is `1`.
  - The picture is saved as `<object-id>.png`, `output/object-path` names the file, and `system/objects` lists the new object. An existing object with the same id is overwritten.
- **More:** [Creating an Object](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/creating-an-object.html), [How To: Find a Part from a Camera Image](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/how-tos/find-a-part-from-a-camera-image.html)

### How tightly should I crop when teaching an object? {#faq-crop-margin}

- **Answer:** Leave about 5 pixels of background around the part; more buys nothing. A crop that stops at the silhouette hides the outline from the detector: the object is either refused as a failed run naming it, or accepted but keyed only on the part’s interior detail. A loose crop that takes in a workbench edge or a neighbouring part makes matching less reliable, because background inside the picture is background the detector then expects to see.
- **More:** [Creating an Object](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/creating-an-object.html)

### How do I switch to another object directory? {#faq-object-dir}

- **Answer:** Write `system/set-object-dir/input/object-dir` and write to `system/set-object-dir/execute`. Do not write `system/object-dir` directly: that changes the value shown but not the directory the application reads. The directory must already exist inside the configuration directory; absolute paths and paths climbing out with `..` are refused with status `-2`. A rejected call changes nothing, and the choice is saved.
- **More:** [Object Storage](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/object-storage.html)

## Finding and tuning

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

- **Answer:** Set `<module>/find-object/input/input-image-address` and `input/object-id`, write to `<module>/find-object/execute` (a blocking call) and read `output/status-code`. `input/object-id` is required: an empty value is refused with `-2`. Each run searches for one object; to sort mixed parts, run once per object and compare the scores. On `1`, read `output/result`: `matches` is sorted by score, so `matches[0]` is the best. Each match gives the top left corner `x`, `y`, the `width` and `height` of the template that matched, the `score` (0 to 1) and the `object_id`. The rectangle is axis aligned; there is no rotation in the result.
- **More:** [Finding an Object](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/finding-an-object.html)

### How do I choose the confidence threshold? {#faq-confidence-threshold}

- **Answer:** Measure rather than guess. Set `input/confidence-threshold` low (`0.4`), run against real parts, note the scores in `output/result`, and set the threshold a little below the worst score a genuine part produces. The default is `0.6`; a threshold at or above `0.9` will usually reject everything. If genuine scores hover near the threshold or images are noisy, set `input/preprocess/blur-sigma-x` to `1.0` (blur is off by default) and measure again.
- **More:** [Tuning the Search](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/tuning-the-search.html)

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

- **Answer:**
  - Restrict the area with `input/crop`; this costs no precision.
  - Raise `input/preprocess/bin-size`. On a 1920x1080 image with a 128x128 object, `2` measured about 6x and `4` about 14x faster. Positions quantise to `bin-size` pixels, and an object binned too far is refused.
  - Search for fewer objects; each `execute` reprocesses the whole image.
  - Keep the settings stable between runs: the detector is compiled on the first run and rebuilt whenever an input changes, which costs far more than a detection.
  - Raising `input/pyramid` does not make the search faster; measured, it is slightly slower.
- **More:** [Tuning the Search: Speed](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/tuning-the-search.html#speed)

### Can the Object 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-object` (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-object/output/result`.
- **More:** [Finding Objects on an Image Stream (Experimental)](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-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:`; invalid inputs are reported together, each naming the input and its value. A failed write to `execute` answers only with a status code (over REST, a bare `400`), so read `output/status-text` afterwards; the text is also in 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.
- **More:** [Execute a Method](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/execute-a-method.html), [Execution Status](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/execution-status.html)

## Troubleshooting {#troubleshooting}

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

- [Status code `-1` (busy)](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/troubleshooting.html#faq-busy-while-streaming)
- [Status code `-2` (invalid input)](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/troubleshooting.html#ts-status-minus-2)
- [Status code `-3` (image read failed)](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/troubleshooting.html#faq-status-minus-3)
- [Status code `-4` (source not found)](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/troubleshooting.html#faq-status-minus-4)
- [The crop region does not fit the image](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/troubleshooting.html#faq-crop-does-not-fit)
- [The run fails and names the object](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/troubleshooting.html#faq-object-refused-bin-size)
- [Status code `-6` (write failed)](https://docs.hdvisionsystems.com/en/lumiscan-object-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-object-finder/1.1.0/troubleshooting.html#faq-empty-result)
- [One part is reported several times](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/troubleshooting.html#faq-duplicate-matches)
- [`output/result` is empty although the search worked a moment ago](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/troubleshooting.html#faq-result-empty-next-run)
- [An uploaded `.png` does not appear on `system/objects`](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/troubleshooting.html#faq-object-not-listed)
- [The image stream delivers no results](https://docs.hdvisionsystems.com/en/lumiscan-object-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-object-finder/1.1.0/troubleshooting.html#faq-settings-lost)
- [The application stops shortly after starting](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/troubleshooting.html#ts-app-stops-after-start)
- [Status code `-11` (licence unavailable)](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/troubleshooting.html#ts-licence-unavailable)

## Modules, 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-object-finder/1.1.0/lumiscan-object-finder/requirements.html#licence), [Module Management](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-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).
- **More:** [Licensing FAQ](https://docs.hdvisionsystems.com/en/lumiscan-licensing/1.0.4/faq.html)

# Troubleshooting – LumiScan Object Finder

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

This page describes problems and error messages of LumiScan Object Finder, grouped by category. Start with the [general checks](https://docs.hdvisionsystems.com/en/lumiscan-object-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-object-finder/1.1.0/lumiscan-object-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-object-finder.json` (`TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `FATAL` or `OFF`). It is read at startup, so restart the application after you change it. See [Data Layer Reference](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/datalayer-reference.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-object-finder/1.1.0/troubleshooting.html#ts-app-stops-after-start).

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

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

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

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

**Symptoms**

`output/status-code` of `find-object` 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-object` 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-object/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-object-finder/1.1.0/lumiscan-object-finder/execute-a-method.html) and [find-object while the stream runs](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-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-object-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) {#ts-status-minus-2}

**Symptoms**

`output/status-code` is `-2`. `output/status-text` starts with `error:` and names each input that cannot be used, together with the value it holds. All invalid inputs are reported together.

**Possible causes**

- A required input is empty. `input/object-id` of `find-object` is required.
- The image address points at this application itself.
- `input/object-id` of `system/create-object` or `input/object-dir` of `system/set-object-dir` is an absolute path, or a path that climbs out of the configuration directory with `..`.

**Diagnostic procedure**

1. Read `output/status-text` of the operation. Expected: it names the offending input and its value.
2. Read the application log. Each invalid input has its own warning line.

**Resolution**

- **If a required input is empty:** set it. For `find-object`, set `input/object-id` to an entry of `system/objects`.
- **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, for example `production-parts`.

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

**If the problem persists**

Send the information listed under [Information for support](https://docs.hdvisionsystems.com/en/lumiscan-object-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-object` or `system/create-object` 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.
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-object-finder/1.1.0/lumiscan-object-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-object-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-object` is `-4`.

**Possible causes**

- The object’s picture is missing or unreadable: `input/object-id` names no entry of `system/objects`.
- The object directory is missing or unreadable.
- The picture is in another directory than the one in use.

**Diagnostic procedure**

1. Compare `input/object-id` with `system/objects`. Expected: the id is listed, spelled the same way.
2. Read `system/object-dir`. Expected: it names the directory that holds the object’s `.png`.
3. Check the file in that directory. Expected: a lower case `.png` at the top of the directory, named after the object.

**Resolution**

- **If the object id is not listed:** correct `input/object-id`, or teach the object with `system/create-object`. A file you put into the directory by other means is listed only after a refresh, see [Problem: An uploaded `.png` does not appear on `system/objects`](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/troubleshooting.html#faq-object-not-listed).
- **If the directory is not the one you expect:** switch with `system/set-object-dir`, see [Object Storage](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/object-storage.html).

Then run `find-object` 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-object-finder/1.1.0/troubleshooting.html#support-information) to support, together with the content of `output/status-text`, `input/object-id`, `system/object-dir` and `system/objects`.

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

**Symptoms**

`system/create-object` answers status `-5` (invalid crop region), and `output/status-text` names the edge and the image size, for example:

```
error: Crop region does not fit inside the 1920x1080 image: crop/startY + crop/height (1000 + 200 = 1200) exceeds the image height 1080
```

For `find-object`, `output/status-text` names the input and the limit it broke, for example `error: crop/startX + crop/width (100 + 900 = 1000) 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. The whole crop must lie inside the image; it is refused, not trimmed.
- For `system/create-object`, `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.

**Resolution**

- **If the region reaches past an edge:** correct `input/crop/startX`, `startY`, `width` or `height`, so that the region fits the image size given in the message.
- **If width or height is 0 (`create-object`):** set both to the size of the region, greater than 0.

Then run the operation again. Expected: `output/status-code` is `1`. See [Creating an Object](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/creating-an-object.html).

**If the problem persists**

Send the information listed under [Information for support](https://docs.hdvisionsystems.com/en/lumiscan-object-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: The run fails and names the object {#faq-object-refused-bin-size}

**Symptoms**

`find-object` fails with a negative status code, and `output/status-text` names the object. This often happens after `input/preprocess/bin-size` was raised. It is never reported as an empty result.

**Possible causes**

- The object is binned too far. Its picture then no longer has the edges the detector keys on, and the detector refuses it, for example a 128x128 object at `bin-size` 8 (reduced to 16x16). Small objects reach this limit sooner than large ones.
- The picture was cropped along the part’s silhouette when the object was taught. A picture must yield a minimum number of strong gradient points, and a crop that stops at the silhouette hides the outline from the detector.

**Diagnostic procedure**

1. Read `input/preprocess/bin-size` of the module. Lower it by one step and run `find-object` again. Expected: `output/status-code` is `1`.
2. If the run still fails at `bin-size` `1`, open the object’s `.png` in the object directory. Expected: a thin, even band of background, about 5 pixels, around the part.

**Resolution**

- **If the object is binned too far:** lower `input/preprocess/bin-size` again. Raise it one step at a time and stop when the scores start dropping towards the threshold.
- **If the picture was cropped at the silhouette:** teach the object again with `system/create-object`, with about 5 pixels of background around the part. See [Creating an Object](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/creating-an-object.html).

See [Tuning the Search: Bin size](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/tuning-the-search.html#bin-size).

**If the problem persists**

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

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

**Symptoms**

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

**Possible causes**

- A file could not be written - usually a permission problem or a full disk.

**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 at the time of the call.
3. Check the configuration directory (see [General checks](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/troubleshooting.html#general-checks)). Expected: it exists and the application can write to it.

**Resolution**

- **If it is a permission problem:** make the configuration directory 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-object-finder/1.1.0/troubleshooting.html#support-information) to support, together with the content of `output/status-text`.

## Search results {#ts-results}

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

**Symptoms**

`output/status-code` of `find-object` is `1`, but `matches` in `output/result` is empty (`best_score` `0.0`, `best_object_id` empty). Or a genuine part is found in some images and missed in others: only in some orientations, or only at some working distances.

**Possible causes**

An empty result with status code `1` means that the object was not in the searched image, and nothing else. Every other reason - missing picture, unusable image, invalid pyramid level, `bin-size` leaving too little of the object - is reported as a negative status code. If a genuine part is missed:

- `input/crop` excludes the part.
- The scores of the genuine parts are below `input/confidence-threshold` (default `0.6`). A threshold at or above `0.9` usually rejects everything.
- The part arrives in an orientation that no object was taught for. The detector does not rotate a picture.
- The part sits closer to or further from the camera than in the picture it was taught from.

**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-object-finder/1.1.0/troubleshooting.html#ts-status-codes).
2. Check that `input/object-id` is listed on `system/objects`.
3. Read the four `input/crop/` values. Expected: all `0` (the whole image), or a region that contains the part.
4. Set `input/confidence-threshold` to `0.4`, run against real parts and note the `score` of the genuine matches in `output/result`. Expected: the threshold you use lies below the worst score of a genuine part.
5. Compare an image in which the part is missed with the image the object was taught from. Expected: the same orientation and working distance.

**Resolution**

- **If the crop excludes the part:** widen the region, or set all four `input/crop/` values to `0`.
- **If the scores are just below the threshold:** set `input/confidence-threshold` a little below the worst score a genuine part produces. If the scores hover near the threshold or the images are noisy, set `input/preprocess/blur-sigma-x` to `1.0` (blur is off by default) and measure again.
- **If the part is missed at particular orientations:** teach another object at the orientation being missed, for example `screw-m6-tilted`, and search for it in its own run. No setting fixes this.
- **If the part is missed at another working distance:** teach an object at that distance.
- **If the part was not in the image:** the result is correct; nothing needs to be changed.

See [Finding an Object](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/finding-an-object.html) and [Tuning the Search](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/tuning-the-search.html).

**If the problem persists**

Send the information listed under [Information for support](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/troubleshooting.html#support-information) to support, together with `input/object-id`, the threshold, the scores you measured and the object’s `.png`.

### Problem: One part is reported several times {#faq-duplicate-matches}

**Symptoms**

`matches` in `output/result` holds a cluster of matches a few pixels apart for one part.

**Possible causes**

- `input/nms-min-dist` is `0` (the default), which keeps every match.
- `input/nms-min-dist` is smaller than the distance between the matches of one part.

**Diagnostic procedure**

1. Read `input/nms-min-dist` of the module. `0` keeps every match.
2. Compare `x` and `y` of the matches of one part with the size of the part in pixels.

**Resolution**

- Set `input/nms-min-dist` to roughly half the size of the part in pixels, for example `40`. Where several matches fall within that distance, only the highest scoring one is kept.

The default of `0` is only useful when parts genuinely sit closer together than their own size. See [Tuning the Search](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/tuning-the-search.html).

**If the problem persists**

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

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

**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. A run that fails for any reason leaves them empty.
- 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-object-finder/1.1.0/lumiscan-object-finder/execute-a-method.html).

**If the problem persists**

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

## Objects {#ts-objects}

### Problem: An uploaded `.png` does not appear on `system/objects` {#faq-object-not-listed}

**Symptoms**

A `.png` file is in the object directory, but `system/objects` does not list it.

**Possible causes**

- The list was not refreshed. `system/objects` is refreshed only at startup, when `system/set-object-dir` switches directory and when `system/create-object` saves a template. Files added by other means - an upload or an SSH session on ctrlX OS, a file copied in by hand on a PC - are picked up at the next of these.
- The file name does not end in a lower case `.png`. `.PNG` files are skipped.
- The file is in a subdirectory. Only files at the top of the object directory are listed.
- The file is in another directory than the one `system/object-dir` names.

**Diagnostic procedure**

1. Read `system/object-dir`. Expected: it names the directory that holds the file.
2. Check the file name. Expected: it ends in a lower case `.png`, and the file is at the top of the directory.

**Resolution**

- **If the file name or the place is wrong:** use a lower case `.png` file name at the top of the object directory.
- **Then:** run `system/set-object-dir` or restart the application. Expected: `system/objects` lists the object.

See [Object Storage](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/object-storage.html).

**If the problem persists**

Send the information listed under [Information for support](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/troubleshooting.html#support-information) to support, together with `system/object-dir`, `system/objects` 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-object` 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: object-id is empty - name the object to search for, see system/objects
   ```

**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-object` call.

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

**If the problem persists**

Send the information listed under [Information for support](https://docs.hdvisionsystems.com/en/lumiscan-object-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 take effect immediately but are not saved until you ask; 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.

**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-object-finder/1.1.0/troubleshooting.html#general-checks)). Expected: `lumiscan-object-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-object-finder/1.1.0/lumiscan-object-finder/module-management.html) and [Kept in the settings file](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-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-object-finder/1.1.0/troubleshooting.html#support-information) to support, together with `lumiscan-object-finder.json` and the module files `<module-id>.json`.

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

**Symptoms**

On ctrlX OS, the application shuts down shortly after it starts. Its nodes under `hdvisionsystems/lumiscan-object-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-object-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 Object Finder, `SWL-W-XCx-OBJECTxFDxHDVS-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-object-finder/1.1.0/lumiscan-object-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-object-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-object-finder/1.1.0/lumiscan-object-finder/module-management.html).

**If the problem persists**

Send the information listed under [Information for support](https://docs.hdvisionsystems.com/en/lumiscan-object-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 Object 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.
- **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-object-finder.json`, the `<module-id>.json` of the module concerned 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-object-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.

# Release Notes: v1.1.0 – LumiScan Object Finder

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

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

## New

**Shape based object detection.** `<module>/find-object/execute` searches a camera image for a known object and reports every occurrence, each with its position, the size of the template that matched, a score and the name of the object. Matching is on gradient orientations rather than pixel intensities, so it tolerates lighting changes and surface texture that defeat intensity correlation.

**An object is one picture**, stored as `<object-dir>/<object-id>.png`, where the file name is the object id. The detector does not rotate or rescale it, so a part that has to be recognised at several orientations is several objects - `screw-m6-front`, `screw-m6-tilted` - searched for in turn. See [Object Storage](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/object-storage.html).

**One object per search.** `<module>/find-object/input/object-id` names the object and is **required**; an empty value is refused with status code `-2`. There is no "search everything" run: a detector is built around one picture, so searching several objects would mean several detectors, and the detector processes the whole image once each time - the expensive part. Running the method once per object keeps that cost visible.

**Teaching from the live camera.** `system/create-object/execute` crops a region out of a camera image and saves it as `<object-id>.png`, so an object can be taught in the real lighting at the real working distance without transferring files. Saving over an existing id replaces it, and `output/object-path` reports where the file landed.

**Several modules**, each with its own `find-object`, settings and results, so one installation can watch several cameras at once. One license is valid for ten modules.

**One object directory for the application**, `system/object-dir`, with the objects in it listed on `system/objects` - one entry per `.png`, which is also the complete list of templates. `system/set-object-dir` changes it and saves the choice.

**A speed setting that works.** `input/preprocess/bin-size` searches at a lower resolution: both the image and the object’s picture are downsampled by that integer factor before matching, so the cost falls with the pixel count. On a full HD image with a 128x128 object, `2` measured about six times faster at an unchanged score and `4` about fourteen times faster. It buys that with precision - positions quantise to `bin-size` pixels - and with detail, since an object binned far enough loses the edges the detector keys on and is refused, which is reported as a failed run rather than as an absent part. Positions are always reported in the pixels of the image you configured. `input/pyramid` reads like a speed setting and is not one: deeper pyramids measured slightly **slower**.

**A region of interest per run**, `input/crop`, and a choice of whether positions are reported in image or crop coordinates.

**A status on every operation**: `output/status-code` and `output/status-text`, where a negative code always means the run failed and produced nothing.

## Worth knowing

The searched region is searched exactly as configured - the detector needs a particular size and pads up to it rather than dropping part of your region. Positions stay exact, so a match reported at y=300 is at y=300 in the image you configured.

An empty result means the object was not in the image, and nothing else. Every other reason a search could come back empty - the object’s picture is missing, the image is unusable, a pyramid level is invalid, the picture has too little contrast for the detector to key on, `bin-size` left too little of it to key on - is caught before the search runs and reported as a negative status code. See [Execution Status](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/lumiscan-object-finder/execution-status.html).

Invalid inputs are all reported together, each naming the offending input and the value it holds.

Objects and the object directory are always interpreted relative to the application’s configuration directory. Absolute paths, and paths leading outside it, are refused.

# LumiScan Object Finder

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

|   |   |   |
| --- | --- | --- |
| ![A screw taught twice, as screw-m6 and as screw-m6-tilted](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/_images/intro/step-1.svg)<br><br>**Teach the object.** From the camera image, one object per orientation. | ![Three screws found and outlined](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/_images/intro/step-2.svg)<br><br>**Find it by its shape.** Matching the outline makes it robust to light and surface finish. | Example result<br><br><br><br><br><br><br>Matches<br>3<br><br><br>Position<br>820, 400 px<br><br><br>Score<br>0.93<br><br><br>Object<br>screw-m6<br><br>**Hand the result to your PLC.** Position, size, score and object name of each match. |

LumiScan Object Finder finds known objects in a camera image by their shape, the edges of their outline, which makes it tolerant of changing light and surface finish. You teach an object from the camera image; the app then reports every match with its position, size, score and object name. Use it for presence and count checks, robot picks, sorting mixed parts on a belt and orientation checks, on ctrlX OS or a Windows or Ubuntu PC.

LumiScan Object 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-object-finder/1.1.0/lumiscan-object-finder/requirements.html#licence). Questions? See the [FAQ](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/faq.html). A problem or an error message? See [Troubleshooting](https://docs.hdvisionsystems.com/en/lumiscan-object-finder/1.1.0/troubleshooting.html).
