This is an automated email from the ASF dual-hosted git repository.
szaszm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git
The following commit(s) were added to refs/heads/main by this push:
new b639ac118 MINIFICPP-2929 Tensor processors: only add mime.type if
content is ov… (#2285)
b639ac118 is described below
commit b639ac118b361c856d7adf1447ac9c71bb6f6ff4
Author: Martin Zink <[email protected]>
AuthorDate: Fri Oct 16 12:02:07 2026 +0200
MINIFICPP-2929 Tensor processors: only add mime.type if content is ov…
(#2285)
* MINIFICPP-2929 Tensor processors: only add mime.type if content is
overwritten
* const IS_REQUIRED: bool = true for everything except Option<T>
---
.github/references/docker_manifest.json | 23 +++--
PROCESSORS.md | 98 +++++++++++-----------
.../extensions/minifi_tensor/minifi_tensor.md | 42 +++++-----
.../src/low_level_processors/classify_output.rs | 27 +++++-
.../classify_image/classify_image_def.rs | 14 ++--
.../processors/detect_object/detect_object_def.rs | 16 ++--
.../src/processors/draw_bounding_box.rs | 3 +-
.../minifi_tensor/src/utils/bounding_box.rs | 2 +-
.../minifi_tensor/src/utils/per_channel_f32.rs | 2 +-
9 files changed, 126 insertions(+), 101 deletions(-)
diff --git a/.github/references/docker_manifest.json
b/.github/references/docker_manifest.json
index 3be2dbd08..4e20333ed 100644
--- a/.github/references/docker_manifest.json
+++ b/.github/references/docker_manifest.json
@@ -13018,7 +13018,7 @@
"name": "Mean",
"description": "Value subtracted from each pixel
before dividing by 'Standard Deviation'. Accepts either a single value
(broadcast to all channels) or three comma-separated values applied per channel
in the order dictated by 'Color format'. Example: '0.485, 0.456, 0.406' for
ImageNet-style RGB normalisation.",
"validator": "VALID",
- "required": "false",
+ "required": "true",
"sensitive": "false",
"expressionLanguageScope": "NONE",
"defaultValue": "0.0"
@@ -13122,7 +13122,7 @@
"name": "Standard Deviation",
"description": "Divisor applied after subtracting
'Mean'. Accepts a single value (broadcast) or three comma-separated values (per
channel). Must be non-zero. Example: '255.0' to scale u8 pixels into [0.0,
1.0]; '0.229, 0.224, 0.225' for ImageNet.",
"validator": "VALID",
- "required": "false",
+ "required": "true",
"sensitive": "false",
"expressionLanguageScope": "NONE",
"defaultValue": "255.0"
@@ -13194,10 +13194,10 @@
},
{
"name": "success",
- "description": "Inference and post-processing
completed. The flow file content is the original, unchanged image; the
classifications are written to the configured output attribute as a JSON array
(may be empty)."
+ "description": "Inference and post-processing
completed. The classifications are written as a JSON array (may be empty) to
the attribute named by 'Output attribute name', leaving the flow file content
as the original image; if that property is empty, they replace the flow file
content instead."
}
],
- "typeDescription": "Runs a full image-classification pass
in a single processor: decodes the image from the flow file content, resizes
and normalises it into an input tensor, runs one inference against the compiled
model owned by the referenced TractModelService, and post-processes the score
vector (score activation, Top-K selection, confidence filtering, optional label
lookup) into predictions. Collapses the ImageToTensor -> InvokeTractModel ->
ClassifyOutput chain i [...]
+ "typeDescription": "Runs a full image-classification pass
in a single processor: decodes the image from the flow file content, resizes
and normalises it into an input tensor, runs one inference against the compiled
model owned by the referenced TractModelService, and post-processes the score
vector (score activation, Top-K selection, confidence filtering, optional label
lookup) into predictions. Collapses the ImageToTensor -> InvokeTractModel ->
ClassifyOutput chain i [...]
"supportsDynamicRelationships": "false",
"supportsDynamicProperties": "false",
"type":
"minifi_tensor.processors.classify_image.ClassifyImage"
@@ -13306,7 +13306,7 @@
"name": "Mean",
"description": "Value subtracted from each pixel
before dividing by 'Standard Deviation'. Accepts either a single value
(broadcast to all channels) or three comma-separated values applied per channel
in the order dictated by 'Color format'. Example: '0.485, 0.456, 0.406' for
ImageNet-style RGB normalisation.",
"validator": "VALID",
- "required": "false",
+ "required": "true",
"sensitive": "false",
"expressionLanguageScope": "NONE",
"defaultValue": "0.0"
@@ -13410,7 +13410,7 @@
"name": "Standard Deviation",
"description": "Divisor applied after subtracting
'Mean'. Accepts a single value (broadcast) or three comma-separated values (per
channel). Must be non-zero. Example: '255.0' to scale u8 pixels into [0.0,
1.0]; '0.229, 0.224, 0.225' for ImageNet.",
"validator": "VALID",
- "required": "false",
+ "required": "true",
"sensitive": "false",
"expressionLanguageScope": "NONE",
"defaultValue": "255.0"
@@ -13473,10 +13473,10 @@
},
{
"name": "success",
- "description": "Inference and post-processing
completed. The flow file content is the original, unchanged image; the detected
boxes are written to the configured output attribute as a JSON array (may be
empty)."
+ "description": "Inference and post-processing
completed. The detected boxes are written as a JSON array (may be empty) to the
attribute named by 'Output attribute name', leaving the flow file content as
the original image; if that property is empty, they replace the flow file
content instead."
}
],
- "typeDescription": "Runs a full object-detection pass in a
single processor: decodes the image from the flow file content, resizes and
normalises it into an input tensor, runs one inference against the compiled
model owned by the referenced TractModelService, and post-processes the model
outputs (score activation, confidence filtering, box decoding, per-class
non-maximum suppression) into bounding boxes. Collapses the ImageToTensor ->
InvokeTractModel -> FilterBoundin [...]
+ "typeDescription": "Runs a full object-detection pass in a
single processor: decodes the image from the flow file content, resizes and
normalises it into an input tensor, runs one inference against the compiled
model owned by the referenced TractModelService, and post-processes the model
outputs (score activation, confidence filtering, box decoding, per-class
non-maximum suppression) into bounding boxes. Collapses the ImageToTensor ->
InvokeTractModel -> FilterBoundin [...]
"supportsDynamicRelationships": "false",
"supportsDynamicProperties": "false",
"type":
"minifi_tensor.processors.detect_object.DetectObject"
@@ -13487,16 +13487,15 @@
"name": "Bounding boxes",
"description": "JSON array of bounding boxes to
draw onto the image (fields class_id, confidence, x_min, y_min, x_max, y_max;
coordinates normalised to [0,1] against the image). Typically the attribute
produced by an upstream DetectObject or FilterBoundingBoxes processor.",
"validator": "VALID",
- "required": "false",
+ "required": "true",
"sensitive": "false",
- "expressionLanguageScope": "FLOWFILE_ATTRIBUTES",
- "defaultValue": "${enrichment.value}"
+ "expressionLanguageScope": "FLOWFILE_ATTRIBUTES"
},
"Line color": {
"name": "Line color",
"description": "Outline color as a hex string
(e.g., '#ff00ff' or '#f0f')",
"validator": "VALID",
- "required": "false",
+ "required": "true",
"sensitive": "false",
"expressionLanguageScope": "NONE",
"defaultValue": "#00FF00"
diff --git a/PROCESSORS.md b/PROCESSORS.md
index a98a5404c..92410256e 100644
--- a/PROCESSORS.md
+++ b/PROCESSORS.md
@@ -224,7 +224,7 @@ In the list below, the names of required properties appear
in bold. Any other pr
### Description
-Runs a full image-classification pass in a single processor: decodes the image
from the flow file content, resizes and normalises it into an input tensor,
runs one inference against the compiled model owned by the referenced
TractModelService, and post-processes the score vector (score activation, Top-K
selection, confidence filtering, optional label lookup) into predictions.
Collapses the ImageToTensor -> InvokeTractModel -> ClassifyOutput chain into
one node. The flow file content is l [...]
+Runs a full image-classification pass in a single processor: decodes the image
from the flow file content, resizes and normalises it into an input tensor,
runs one inference against the compiled model owned by the referenced
TractModelService, and post-processes the score vector (score activation, Top-K
selection, confidence filtering, optional label lookup) into predictions.
Collapses the ImageToTensor -> InvokeTractModel -> ClassifyOutput chain into
one node. The Top-K classifications [...]
### Properties
@@ -232,41 +232,41 @@ In the list below, the names of required properties
appear in bold. Any other pr
| Name | Default Value | Allowable Values
| Description
[...]
|--------------------------|---------------|-----------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
[...]
-| **Target width** | |
| Width in pixels the decoded image is resized to before
normalisation and inference.
[...]
-| **Target height** | |
| Height in pixels the decoded image is resized to before
normalisation and inference.
[...]
-| **Resize filter** | Bilinear |
Nearest<br/>Bilinear<br/>Bicubic<br/>Lanczos3 | Interpolation filter applied
when resizing the decoded image. Nearest is fastest but blocky; Bilinear is a
good default; Bicubic and Lanczos3 are higher-quality but slower.
[...]
-| **Resize mode** | Stretch | Stretch<br/>Letterbox
| How the source image is fitted into the target dimensions.
'Stretch' scales each axis independently, distorting aspect ratio. 'Letterbox'
preserves aspect ratio and pads the remaining border with 'Letterbox pad value'
(applied in normalised output space).
[...]
-| **Letterbox pad value** | 0.0 |
| Value written for padding pixels when 'Resize mode' is
'Letterbox'. This is a normalised value (post mean/std), so 0.0 corresponds to
a neutral input for most networks. Ignored when 'Resize mode' is 'Stretch'.
[...]
| **Color format** | RGB | RGB<br/>BGR<br/>Grayscale
| Color space of the tensor fed to the model. RGB and BGR produce
three-channel tensors (channel order determined by the format); Grayscale
produces a single-channel luma tensor.
[...]
-| **Tensor shape format** | CHW | CHW<br/>HWC
| Memory layout of the tensor fed to the model. CHW
(channels-first) is typical for PyTorch/ONNX detectors. HWC (channels-last)
matches TensorFlow/TFLite. Ignored for Grayscale (always effectively 1xHxW).
[...]
-| Mean | 0.0 |
| Value subtracted from each pixel before dividing by 'Standard
Deviation'. Accepts either a single value (broadcast to all channels) or three
comma-separated values applied per channel in the order dictated by 'Color
format'. Example: '0.485, 0.456, 0.406' for ImageNet-style RGB normalisation.
[...]
-| Standard Deviation | 255.0 |
| Divisor applied after subtracting 'Mean'. Accepts a single value
(broadcast) or three comma-separated values (per channel). Must be non-zero.
Example: '255.0' to scale u8 pixels into [0.0, 1.0]; '0.229, 0.224, 0.225' for
ImageNet.
[...]
-| **Pixel divisor** | 1.0 |
| Divisor applied to raw u8 pixel values before subtracting 'Mean'
and dividing by 'Standard Deviation'. Defaults to 1.0 (mean/std interpreted in
[0, 255] pixel space, e.g. UltraFace's mean=127, std=128). Set to 255 to bring
pixels into [0.0, 1.0] first so ImageNet-style mean/std values like '0.485,
0.456, 0.406' / '0.229, 0.224, 0.225' can be used directly, matching the
PyTorch / torchvision / ONN [...]
-| **Tract model service** | |
| Reference to a TractModelService controller service. The
referenced service owns the compiled model (ONNX or NNEF) that will be
evaluated for each incoming flow file.
[...]
-| **Top K** | 5 |
| Number of highest-scoring classes to include in the output JSON,
in descending order of confidence. Values above the total class count are
clamped. Set to 1 for pure top-1 classification.
[...]
-| **Score output index** | 0 |
| Zero-based index of the model output tensor that holds
classification scores. The processor slices the concatenated payload from
InvokeTractModel according to the 'tensor.N.bytes' attributes. Almost always 0
for single-head classifiers.
[...]
-| **Score activation** | Softmax | Softmax<br/>Sigmoid<br/>None
| Activation applied to the raw score vector before ranking.
Softmax = mutually-exclusive classes (ImageNet-trained
ResNet/MobileNet/EfficientNet raw logits). Sigmoid = independent classes
(multi-label classifiers). None = the model already emits probabilities/scores;
rank the raw values.
[...]
| **Confidence Threshold** | 0.0 |
| Minimum confidence a class must reach to be included in the
output JSON. Applied AFTER activation, so the units match the chosen activation
(0.0..=1.0 for Softmax/Sigmoid, model-native for None). Set to 0.0 to always
emit exactly Top K predictions.<br/>**Supports Expression Language: true**
[...]
-| Labels file path | |
| Optional path to a newline-separated labels file (line N = name
of class N). Loaded once at service enable time. When set, each prediction in
the output JSON gains a 'class_name' field and the 'class.top1.name' flow file
attribute is populated. Leave empty to emit numeric class IDs only.
[...]
| Label index offset | |
| Offset added to the model's class ID when looking up a name in
the labels file. Defaults to 0 (labels file line N = class N). Set to 1 for
label files that start with a dummy/background entry — e.g. the ONNX
MobileNetV2 model emits 1000 class scores while 'imagenet_slim_labels.txt' has
1001 lines (line 0 = 'dummy'), so class ID 653 maps to line 654 = 'military
uniform'. [...]
+| Labels file path | |
| Optional path to a newline-separated labels file (line N = name
of class N). Loaded once at service enable time. When set, each prediction in
the output JSON gains a 'class_name' field and the 'class.top1.name' flow file
attribute is populated. Leave empty to emit numeric class IDs only.
[...]
+| **Letterbox pad value** | 0.0 |
| Value written for padding pixels when 'Resize mode' is
'Letterbox'. This is a normalised value (post mean/std), so 0.0 corresponds to
a neutral input for most networks. Ignored when 'Resize mode' is 'Stretch'.
[...]
+| **Mean** | 0.0 |
| Value subtracted from each pixel before dividing by 'Standard
Deviation'. Accepts either a single value (broadcast to all channels) or three
comma-separated values applied per channel in the order dictated by 'Color
format'. Example: '0.485, 0.456, 0.406' for ImageNet-style RGB normalisation.
[...]
| Output attribute name | |
| Specify the attribute to use as output, if not provided, the
content is overridden instead.<br/>**Supports Expression Language: true**
[...]
+| **Pixel divisor** | 1.0 |
| Divisor applied to raw u8 pixel values before subtracting 'Mean'
and dividing by 'Standard Deviation'. Defaults to 1.0 (mean/std interpreted in
[0, 255] pixel space, e.g. UltraFace's mean=127, std=128). Set to 255 to bring
pixels into [0.0, 1.0] first so ImageNet-style mean/std values like '0.485,
0.456, 0.406' / '0.229, 0.224, 0.225' can be used directly, matching the
PyTorch / torchvision / ONN [...]
+| **Resize filter** | Bilinear |
Nearest<br/>Bilinear<br/>Bicubic<br/>Lanczos3 | Interpolation filter applied
when resizing the decoded image. Nearest is fastest but blocky; Bilinear is a
good default; Bicubic and Lanczos3 are higher-quality but slower.
[...]
+| **Resize mode** | Stretch | Stretch<br/>Letterbox
| How the source image is fitted into the target dimensions.
'Stretch' scales each axis independently, distorting aspect ratio. 'Letterbox'
preserves aspect ratio and pads the remaining border with 'Letterbox pad value'
(applied in normalised output space).
[...]
+| **Score activation** | Softmax | Softmax<br/>Sigmoid<br/>None
| Activation applied to the raw score vector before ranking.
Softmax = mutually-exclusive classes (ImageNet-trained
ResNet/MobileNet/EfficientNet raw logits). Sigmoid = independent classes
(multi-label classifiers). None = the model already emits probabilities/scores;
rank the raw values.
[...]
+| **Score output index** | 0 |
| Zero-based index of the model output tensor that holds
classification scores. The processor slices the concatenated payload from
InvokeTractModel according to the 'tensor.N.bytes' attributes. Almost always 0
for single-head classifiers.
[...]
+| **Standard Deviation** | 255.0 |
| Divisor applied after subtracting 'Mean'. Accepts a single value
(broadcast) or three comma-separated values (per channel). Must be non-zero.
Example: '255.0' to scale u8 pixels into [0.0, 1.0]; '0.229, 0.224, 0.225' for
ImageNet.
[...]
+| **Target height** | |
| Height in pixels the decoded image is resized to before
normalisation and inference.
[...]
+| **Target width** | |
| Width in pixels the decoded image is resized to before
normalisation and inference.
[...]
+| **Tensor shape format** | CHW | CHW<br/>HWC
| Memory layout of the tensor fed to the model. CHW
(channels-first) is typical for PyTorch/ONNX detectors. HWC (channels-last)
matches TensorFlow/TFLite. Ignored for Grayscale (always effectively 1xHxW).
[...]
+| **Top K** | 5 |
| Number of highest-scoring classes to include in the output JSON,
in descending order of confidence. Values above the total class count are
clamped. Set to 1 for pure top-1 classification.
[...]
+| **Tract model service** | |
| Reference to a TractModelService controller service. The
referenced service owns the compiled model (ONNX or NNEF) that will be
evaluated for each incoming flow file.
[...]
### Relationships
-| Name | Description
|
-|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| success | Inference and post-processing completed. The flow file content is
the original, unchanged image; the classifications are written to the
configured output attribute as a JSON array (may be empty). |
-| failure | The image could not be decoded, the input tensor could not be
built, the model failed to run, or the model outputs could not be interpreted
as classification. |
+| Name | Description
|
+|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| failure | The image could not be decoded, the input tensor could not be
built, the model failed to run, or the model outputs could not be interpreted
as classification.
|
+| success | Inference and post-processing completed. The classifications are
written as a JSON array (may be empty) to the attribute named by 'Output
attribute name', leaving the flow file content as the original image; if that
property is empty, they replace the flow file content instead. |
### Output Attributes
| Attribute | Relationship | Description
|
|-----------------------|--------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| mime.type | success | If the "Output attribute name" is
None, then the content will be overridden with the JSON array of objects with
fields class_id, confidence, and optional class_name, and the mime type will be
set to 'application/json'. |
| class.count | success | Number of predictions retained after
Top K selection and confidence filtering.
|
-| class.top1.id | success | Numeric class ID of the
highest-confidence prediction, when at least one prediction cleared the
confidence threshold.
|
| class.top1.confidence | success | Confidence (post-activation) of the
highest-confidence prediction, when at least one prediction cleared the
confidence threshold.
|
+| class.top1.id | success | Numeric class ID of the
highest-confidence prediction, when at least one prediction cleared the
confidence threshold.
|
| class.top1.name | success | Label of the highest-confidence
prediction. Only present when 'Labels file path' was configured and at least
one prediction cleared the threshold.
|
+| mime.type | success | If the "Output attribute name" is
None, then the content will be overridden with the JSON array of objects with
fields class_id, confidence, and optional class_name, and the mime type will be
set to 'application/json'. |
## CollectKubernetesPodMetrics
@@ -697,7 +697,7 @@ In the list below, the names of required properties appear
in bold. Any other pr
### Description
-Runs a full object-detection pass in a single processor: decodes the image
from the flow file content, resizes and normalises it into an input tensor,
runs one inference against the compiled model owned by the referenced
TractModelService, and post-processes the model outputs (score activation,
confidence filtering, box decoding, per-class non-maximum suppression) into
bounding boxes. Collapses the ImageToTensor -> InvokeTractModel ->
FilterBoundingBoxes chain into one node. The flow fil [...]
+Runs a full object-detection pass in a single processor: decodes the image
from the flow file content, resizes and normalises it into an input tensor,
runs one inference against the compiled model owned by the referenced
TractModelService, and post-processes the model outputs (score activation,
confidence filtering, box decoding, per-class non-maximum suppression) into
bounding boxes. Collapses the ImageToTensor -> InvokeTractModel ->
FilterBoundingBoxes chain into one node. The detected [...]
### Properties
@@ -705,40 +705,40 @@ In the list below, the names of required properties
appear in bold. Any other pr
| Name | Default Value | Allowable Values
| Description
[...]
|--------------------------|---------------|-----------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
[...]
-| **Target width** | |
| Width in pixels the decoded image is resized to before
normalisation and inference.
[...]
-| **Target height** | |
| Height in pixels the decoded image is resized to before
normalisation and inference.
[...]
-| **Resize filter** | Bilinear |
Nearest<br/>Bilinear<br/>Bicubic<br/>Lanczos3 | Interpolation filter applied
when resizing the decoded image. Nearest is fastest but blocky; Bilinear is a
good default; Bicubic and Lanczos3 are higher-quality but slower.
[...]
-| **Resize mode** | Stretch | Stretch<br/>Letterbox
| How the source image is fitted into the target dimensions.
'Stretch' scales each axis independently, distorting aspect ratio. 'Letterbox'
preserves aspect ratio and pads the remaining border with 'Letterbox pad value'
(applied in normalised output space).
[...]
-| **Letterbox pad value** | 0.0 |
| Value written for padding pixels when 'Resize mode' is
'Letterbox'. This is a normalised value (post mean/std), so 0.0 corresponds to
a neutral input for most networks. Ignored when 'Resize mode' is 'Stretch'.
[...]
+| Background class index | |
| Index of the 'background / no-object' class. Boxes whose winning
class equals this index are dropped. In score-matrix mode this is only honoured
when the score tensor has more than one class per box; in 'Class output index'
mode it is matched against each box's class id.
[...]
+| **Box format** | Xyxy | Xyxy<br/>Yxyx<br/>Cxcywh
| Layout of the four floats per box in the box output tensor. Xyxy
= [x_min, y_min, x_max, y_max] (SSD, MobileNet-SSD, most PyTorch exports). Yxyx
= [y_min, x_min, y_max, x_max] (TensorFlow Object Detection API). Cxcywh = [cx,
cy, w, h] (YOLOv3/5/8 raw output).
[...]
+| **Box output index** | 1 |
| Zero-based index of the model output tensor that holds box
coordinates. Must differ from 'Score output index'.
[...]
+| Class output index | |
| Zero-based index of a model output tensor that holds one class id
per box. Set this for detectors that emit boxes, per-box scores, and class ids
as three separate parallel tensors, with NMS already folded into the graph
(TensorFlow Object Detection API; YOLO / EfficientNMS 'end2end' exports). When
set, 'Score output index' is read as one score per box (not a [boxes, classes]
matrix) and no argmax [...]
| **Color format** | RGB | RGB<br/>BGR<br/>Grayscale
| Color space of the tensor fed to the model. RGB and BGR produce
three-channel tensors (channel order determined by the format); Grayscale
produces a single-channel luma tensor.
[...]
-| **Tensor shape format** | CHW | CHW<br/>HWC
| Memory layout of the tensor fed to the model. CHW
(channels-first) is typical for PyTorch/ONNX detectors. HWC (channels-last)
matches TensorFlow/TFLite. Ignored for Grayscale (always effectively 1xHxW).
[...]
-| Mean | 0.0 |
| Value subtracted from each pixel before dividing by 'Standard
Deviation'. Accepts either a single value (broadcast to all channels) or three
comma-separated values applied per channel in the order dictated by 'Color
format'. Example: '0.485, 0.456, 0.406' for ImageNet-style RGB normalisation.
[...]
-| Standard Deviation | 255.0 |
| Divisor applied after subtracting 'Mean'. Accepts a single value
(broadcast) or three comma-separated values (per channel). Must be non-zero.
Example: '255.0' to scale u8 pixels into [0.0, 1.0]; '0.229, 0.224, 0.225' for
ImageNet.
[...]
-| **Pixel divisor** | 1.0 |
| Divisor applied to raw u8 pixel values before subtracting 'Mean'
and dividing by 'Standard Deviation'. Defaults to 1.0 (mean/std interpreted in
[0, 255] pixel space, e.g. UltraFace's mean=127, std=128). Set to 255 to bring
pixels into [0.0, 1.0] first so ImageNet-style mean/std values like '0.485,
0.456, 0.406' / '0.229, 0.224, 0.225' can be used directly, matching the
PyTorch / torchvision / ONN [...]
-| **Tract model service** | |
| Reference to a TractModelService controller service. The
referenced service owns the compiled model (ONNX or NNEF) that will be
evaluated for each incoming flow file.
[...]
| **Confidence Threshold** | 0.7 |
| Minimum per-box class probability (0.0 to 1.0) required to keep a
bounding box after applying the chosen 'Score activation'. Boxes below the
threshold are discarded before NMS.<br/>**Supports Expression Language: true**
[...]
| **IoU Threshold** | 0.45 |
| Intersection-over-union cutoff used during non-maximum
suppression. Boxes of the same class whose IoU with a higher-confidence peer
exceeds this value are suppressed. Typical values: 0.45 (SSD/YOLO default),
0.5, 0.3 for stricter deduplication.
[...]
-| **Score output index** | 0 |
| Zero-based index of the model output tensor that holds
classification scores. The processor slices the concatenated payload from
InvokeTractModel according to the 'tensor.N.bytes' attributes.
[...]
-| **Box output index** | 1 |
| Zero-based index of the model output tensor that holds box
coordinates. Must differ from 'Score output index'.
[...]
-| Class output index | |
| Zero-based index of a model output tensor that holds one class id
per box. Set this for detectors that emit boxes, per-box scores, and class ids
as three separate parallel tensors, with NMS already folded into the graph
(TensorFlow Object Detection API; YOLO / EfficientNMS 'end2end' exports). When
set, 'Score output index' is read as one score per box (not a [boxes, classes]
matrix) and no argmax [...]
-| **Box format** | Xyxy | Xyxy<br/>Yxyx<br/>Cxcywh
| Layout of the four floats per box in the box output tensor. Xyxy
= [x_min, y_min, x_max, y_max] (SSD, MobileNet-SSD, most PyTorch exports). Yxyx
= [y_min, x_min, y_max, x_max] (TensorFlow Object Detection API). Cxcywh = [cx,
cy, w, h] (YOLOv3/5/8 raw output).
[...]
-| **Score activation** | Softmax | Softmax<br/>Sigmoid<br/>None
| Activation applied to raw per-class scores before selecting the
winning class. Softmax = mutually-exclusive classes (SSD/MobileNet-SSD raw
logits). Sigmoid = independent classes (YOLOv5/v8 style). None = the model
already emits probabilities/scores; use raw argmax with the raw score as
confidence.
[...]
-| Background class index | |
| Index of the 'background / no-object' class. Boxes whose winning
class equals this index are dropped. In score-matrix mode this is only honoured
when the score tensor has more than one class per box; in 'Class output index'
mode it is matched against each box's class id.
[...]
+| **Letterbox pad value** | 0.0 |
| Value written for padding pixels when 'Resize mode' is
'Letterbox'. This is a normalised value (post mean/std), so 0.0 corresponds to
a neutral input for most networks. Ignored when 'Resize mode' is 'Stretch'.
[...]
+| **Mean** | 0.0 |
| Value subtracted from each pixel before dividing by 'Standard
Deviation'. Accepts either a single value (broadcast to all channels) or three
comma-separated values applied per channel in the order dictated by 'Color
format'. Example: '0.485, 0.456, 0.406' for ImageNet-style RGB normalisation.
[...]
| Output attribute name | |
| Specify the attribute to use as output, if not provided, the
content is overridden instead.<br/>**Supports Expression Language: true**
[...]
+| **Pixel divisor** | 1.0 |
| Divisor applied to raw u8 pixel values before subtracting 'Mean'
and dividing by 'Standard Deviation'. Defaults to 1.0 (mean/std interpreted in
[0, 255] pixel space, e.g. UltraFace's mean=127, std=128). Set to 255 to bring
pixels into [0.0, 1.0] first so ImageNet-style mean/std values like '0.485,
0.456, 0.406' / '0.229, 0.224, 0.225' can be used directly, matching the
PyTorch / torchvision / ONN [...]
+| **Resize filter** | Bilinear |
Nearest<br/>Bilinear<br/>Bicubic<br/>Lanczos3 | Interpolation filter applied
when resizing the decoded image. Nearest is fastest but blocky; Bilinear is a
good default; Bicubic and Lanczos3 are higher-quality but slower.
[...]
+| **Resize mode** | Stretch | Stretch<br/>Letterbox
| How the source image is fitted into the target dimensions.
'Stretch' scales each axis independently, distorting aspect ratio. 'Letterbox'
preserves aspect ratio and pads the remaining border with 'Letterbox pad value'
(applied in normalised output space).
[...]
+| **Score activation** | Softmax | Softmax<br/>Sigmoid<br/>None
| Activation applied to raw per-class scores before selecting the
winning class. Softmax = mutually-exclusive classes (SSD/MobileNet-SSD raw
logits). Sigmoid = independent classes (YOLOv5/v8 style). None = the model
already emits probabilities/scores; use raw argmax with the raw score as
confidence.
[...]
+| **Score output index** | 0 |
| Zero-based index of the model output tensor that holds
classification scores. The processor slices the concatenated payload from
InvokeTractModel according to the 'tensor.N.bytes' attributes.
[...]
+| **Standard Deviation** | 255.0 |
| Divisor applied after subtracting 'Mean'. Accepts a single value
(broadcast) or three comma-separated values (per channel). Must be non-zero.
Example: '255.0' to scale u8 pixels into [0.0, 1.0]; '0.229, 0.224, 0.225' for
ImageNet.
[...]
+| **Target height** | |
| Height in pixels the decoded image is resized to before
normalisation and inference.
[...]
+| **Target width** | |
| Width in pixels the decoded image is resized to before
normalisation and inference.
[...]
+| **Tensor shape format** | CHW | CHW<br/>HWC
| Memory layout of the tensor fed to the model. CHW
(channels-first) is typical for PyTorch/ONNX detectors. HWC (channels-last)
matches TensorFlow/TFLite. Ignored for Grayscale (always effectively 1xHxW).
[...]
+| **Tract model service** | |
| Reference to a TractModelService controller service. The
referenced service owns the compiled model (ONNX or NNEF) that will be
evaluated for each incoming flow file.
[...]
### Relationships
-| Name | Description
|
-|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| success | Inference and post-processing completed. The flow file content is
the original, unchanged image; the detected boxes are written to the configured
output attribute as a JSON array (may be empty). |
-| failure | The image could not be decoded, the input tensor could not be
built, the model failed to run, or the model outputs could not be interpreted
as scores + boxes. |
+| Name | Description
|
+|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| failure | The image could not be decoded, the input tensor could not be
built, the model failed to run, or the model outputs could not be interpreted
as scores + boxes.
|
+| success | Inference and post-processing completed. The detected boxes are
written as a JSON array (may be empty) to the attribute named by 'Output
attribute name', leaving the flow file content as the original image; if that
property is empty, they replace the flow file content instead. |
### Output Attributes
| Attribute | Relationship | Description
|
|-------------------------|--------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| object.count | success | Number of bounding boxes retained
after confidence filtering and NMS.
|
| <Output attribute name> | success | JSON array of the surviving
bounding boxes (fields class_id, confidence, x_min, y_min, x_max, y_max;
coordinates normalised to [0,1] against the original image). The attribute name
is configurable via the 'Output attribute name' property. |
+| object.count | success | Number of bounding boxes retained
after confidence filtering and NMS.
|
## DrawBoundingBox
@@ -751,18 +751,18 @@ Decodes the image from the flow file content, draws each
bounding box supplied v
In the list below, the names of required properties appear in bold. Any other
properties (not in bold) are considered optional. The table also indicates any
default values, and whether a property supports the NiFi Expression Language.
-| Name | Default Value | Allowable Values | Description
|
-|--------------------|---------------------|------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| Bounding boxes | ${enrichment.value} | | JSON array of
bounding boxes to draw onto the image (fields class_id, confidence, x_min,
y_min, x_max, y_max; coordinates normalised to [0,1] against the image).
Typically the attribute produced by an upstream DetectObject or
FilterBoundingBoxes processor.<br/>**Supports Expression Language: true** |
-| Line color | #00FF00 | | Outline color
as a hex string (e.g., '#ff00ff' or '#f0f')
|
-| **Line thickness** | 5 | | Thickness in
pixels of the drawn box outline.
|
+| Name | Default Value | Allowable Values | Description
|
+|--------------------|---------------|------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **Bounding boxes** | | | JSON array of
bounding boxes to draw onto the image (fields class_id, confidence, x_min,
y_min, x_max, y_max; coordinates normalised to [0,1] against the image).
Typically the attribute produced by an upstream DetectObject or
FilterBoundingBoxes processor.<br/>**Supports Expression Language: true** |
+| **Line color** | #00FF00 | | Outline color as a
hex string (e.g., '#ff00ff' or '#f0f')
|
+| **Line thickness** | 5 | | Thickness in pixels
of the drawn box outline.
|
### Relationships
| Name | Description |
|---------|------------------------------------------------------------|
-| success | Flowfiles are routed here after drawing the bounding boxes |
| failure | Invalid FlowFiles are routed here |
+| success | Flowfiles are routed here after drawing the bounding boxes |
## EncryptContentPGP
diff --git a/minifi_rust/extensions/minifi_tensor/minifi_tensor.md
b/minifi_rust/extensions/minifi_tensor/minifi_tensor.md
index 1301446b4..cbb0a9d70 100644
--- a/minifi_rust/extensions/minifi_tensor/minifi_tensor.md
+++ b/minifi_rust/extensions/minifi_tensor/minifi_tensor.md
@@ -33,7 +33,7 @@ limitations under the License.
### Description
-Runs a full image-classification pass in a single processor: decodes the image
from the flow file content, resizes and normalises it into an input tensor,
runs one inference against the compiled model owned by the referenced
TractModelService, and post-processes the score vector (score activation, Top-K
selection, confidence filtering, optional label lookup) into predictions.
Collapses the ImageToTensor -> InvokeTractModel -> ClassifyOutput chain into
one node. The flow file content is l [...]
+Runs a full image-classification pass in a single processor: decodes the image
from the flow file content, resizes and normalises it into an input tensor,
runs one inference against the compiled model owned by the referenced
TractModelService, and post-processes the score vector (score activation, Top-K
selection, confidence filtering, optional label lookup) into predictions.
Collapses the ImageToTensor -> InvokeTractModel -> ClassifyOutput chain into
one node. The Top-K classifications [...]
### Properties
@@ -46,14 +46,14 @@ In the list below, the names of required properties appear
in bold. Any other pr
| Label index offset | |
| Offset added to the model's class ID when looking up a name in
the labels file. Defaults to 0 (labels file line N = class N). Set to 1 for
label files that start with a dummy/background entry — e.g. the ONNX
MobileNetV2 model emits 1000 class scores while 'imagenet_slim_labels.txt' has
1001 lines (line 0 = 'dummy'), so class ID 653 maps to line 654 = 'military
uniform'. [...]
| Labels file path | |
| Optional path to a newline-separated labels file (line N = name
of class N). Loaded once at service enable time. When set, each prediction in
the output JSON gains a 'class_name' field and the 'class.top1.name' flow file
attribute is populated. Leave empty to emit numeric class IDs only.
[...]
| **Letterbox pad value** | 0.0 |
| Value written for padding pixels when 'Resize mode' is
'Letterbox'. This is a normalised value (post mean/std), so 0.0 corresponds to
a neutral input for most networks. Ignored when 'Resize mode' is 'Stretch'.
[...]
-| Mean | 0.0 |
| Value subtracted from each pixel before dividing by 'Standard
Deviation'. Accepts either a single value (broadcast to all channels) or three
comma-separated values applied per channel in the order dictated by 'Color
format'. Example: '0.485, 0.456, 0.406' for ImageNet-style RGB normalisation.
[...]
+| **Mean** | 0.0 |
| Value subtracted from each pixel before dividing by 'Standard
Deviation'. Accepts either a single value (broadcast to all channels) or three
comma-separated values applied per channel in the order dictated by 'Color
format'. Example: '0.485, 0.456, 0.406' for ImageNet-style RGB normalisation.
[...]
| Output attribute name | |
| Specify the attribute to use as output, if not provided, the
content is overridden instead.<br/>**Supports Expression Language: true**
[...]
| **Pixel divisor** | 1.0 |
| Divisor applied to raw u8 pixel values before subtracting 'Mean'
and dividing by 'Standard Deviation'. Defaults to 1.0 (mean/std interpreted in
[0, 255] pixel space, e.g. UltraFace's mean=127, std=128). Set to 255 to bring
pixels into [0.0, 1.0] first so ImageNet-style mean/std values like '0.485,
0.456, 0.406' / '0.229, 0.224, 0.225' can be used directly, matching the
PyTorch / torchvision / ONN [...]
| **Resize filter** | Bilinear |
Nearest<br/>Bilinear<br/>Bicubic<br/>Lanczos3 | Interpolation filter applied
when resizing the decoded image. Nearest is fastest but blocky; Bilinear is a
good default; Bicubic and Lanczos3 are higher-quality but slower.
[...]
| **Resize mode** | Stretch | Stretch<br/>Letterbox
| How the source image is fitted into the target dimensions.
'Stretch' scales each axis independently, distorting aspect ratio. 'Letterbox'
preserves aspect ratio and pads the remaining border with 'Letterbox pad value'
(applied in normalised output space).
[...]
| **Score activation** | Softmax | Softmax<br/>Sigmoid<br/>None
| Activation applied to the raw score vector before ranking.
Softmax = mutually-exclusive classes (ImageNet-trained
ResNet/MobileNet/EfficientNet raw logits). Sigmoid = independent classes
(multi-label classifiers). None = the model already emits probabilities/scores;
rank the raw values.
[...]
| **Score output index** | 0 |
| Zero-based index of the model output tensor that holds
classification scores. The processor slices the concatenated payload from
InvokeTractModel according to the 'tensor.N.bytes' attributes. Almost always 0
for single-head classifiers.
[...]
-| Standard Deviation | 255.0 |
| Divisor applied after subtracting 'Mean'. Accepts a single value
(broadcast) or three comma-separated values (per channel). Must be non-zero.
Example: '255.0' to scale u8 pixels into [0.0, 1.0]; '0.229, 0.224, 0.225' for
ImageNet.
[...]
+| **Standard Deviation** | 255.0 |
| Divisor applied after subtracting 'Mean'. Accepts a single value
(broadcast) or three comma-separated values (per channel). Must be non-zero.
Example: '255.0' to scale u8 pixels into [0.0, 1.0]; '0.229, 0.224, 0.225' for
ImageNet.
[...]
| **Target height** | |
| Height in pixels the decoded image is resized to before
normalisation and inference.
[...]
| **Target width** | |
| Width in pixels the decoded image is resized to before
normalisation and inference.
[...]
| **Tensor shape format** | CHW | CHW<br/>HWC
| Memory layout of the tensor fed to the model. CHW
(channels-first) is typical for PyTorch/ONNX detectors. HWC (channels-last)
matches TensorFlow/TFLite. Ignored for Grayscale (always effectively 1xHxW).
[...]
@@ -62,10 +62,10 @@ In the list below, the names of required properties appear
in bold. Any other pr
### Relationships
-| Name | Description
|
-|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| failure | The image could not be decoded, the input tensor could not be
built, the model failed to run, or the model outputs could not be interpreted
as classification. |
-| success | Inference and post-processing completed. The flow file content is
the original, unchanged image; the classifications are written to the
configured output attribute as a JSON array (may be empty). |
+| Name | Description
|
+|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| failure | The image could not be decoded, the input tensor could not be
built, the model failed to run, or the model outputs could not be interpreted
as classification.
|
+| success | Inference and post-processing completed. The classifications are
written as a JSON array (may be empty) to the attribute named by 'Output
attribute name', leaving the flow file content as the original image; if that
property is empty, they replace the flow file content instead. |
### Output Attributes
@@ -120,7 +120,7 @@ In the list below, the names of required properties appear
in bold. Any other pr
### Description
-Runs a full object-detection pass in a single processor: decodes the image
from the flow file content, resizes and normalises it into an input tensor,
runs one inference against the compiled model owned by the referenced
TractModelService, and post-processes the model outputs (score activation,
confidence filtering, box decoding, per-class non-maximum suppression) into
bounding boxes. Collapses the ImageToTensor -> InvokeTractModel ->
FilterBoundingBoxes chain into one node. The flow fil [...]
+Runs a full object-detection pass in a single processor: decodes the image
from the flow file content, resizes and normalises it into an input tensor,
runs one inference against the compiled model owned by the referenced
TractModelService, and post-processes the model outputs (score activation,
confidence filtering, box decoding, per-class non-maximum suppression) into
bounding boxes. Collapses the ImageToTensor -> InvokeTractModel ->
FilterBoundingBoxes chain into one node. The detected [...]
### Properties
@@ -136,14 +136,14 @@ In the list below, the names of required properties
appear in bold. Any other pr
| **Confidence Threshold** | 0.7 |
| Minimum per-box class probability (0.0 to 1.0) required to keep a
bounding box after applying the chosen 'Score activation'. Boxes below the
threshold are discarded before NMS.<br/>**Supports Expression Language: true**
[...]
| **IoU Threshold** | 0.45 |
| Intersection-over-union cutoff used during non-maximum
suppression. Boxes of the same class whose IoU with a higher-confidence peer
exceeds this value are suppressed. Typical values: 0.45 (SSD/YOLO default),
0.5, 0.3 for stricter deduplication.
[...]
| **Letterbox pad value** | 0.0 |
| Value written for padding pixels when 'Resize mode' is
'Letterbox'. This is a normalised value (post mean/std), so 0.0 corresponds to
a neutral input for most networks. Ignored when 'Resize mode' is 'Stretch'.
[...]
-| Mean | 0.0 |
| Value subtracted from each pixel before dividing by 'Standard
Deviation'. Accepts either a single value (broadcast to all channels) or three
comma-separated values applied per channel in the order dictated by 'Color
format'. Example: '0.485, 0.456, 0.406' for ImageNet-style RGB normalisation.
[...]
+| **Mean** | 0.0 |
| Value subtracted from each pixel before dividing by 'Standard
Deviation'. Accepts either a single value (broadcast to all channels) or three
comma-separated values applied per channel in the order dictated by 'Color
format'. Example: '0.485, 0.456, 0.406' for ImageNet-style RGB normalisation.
[...]
| Output attribute name | |
| Specify the attribute to use as output, if not provided, the
content is overridden instead.<br/>**Supports Expression Language: true**
[...]
| **Pixel divisor** | 1.0 |
| Divisor applied to raw u8 pixel values before subtracting 'Mean'
and dividing by 'Standard Deviation'. Defaults to 1.0 (mean/std interpreted in
[0, 255] pixel space, e.g. UltraFace's mean=127, std=128). Set to 255 to bring
pixels into [0.0, 1.0] first so ImageNet-style mean/std values like '0.485,
0.456, 0.406' / '0.229, 0.224, 0.225' can be used directly, matching the
PyTorch / torchvision / ONN [...]
| **Resize filter** | Bilinear |
Nearest<br/>Bilinear<br/>Bicubic<br/>Lanczos3 | Interpolation filter applied
when resizing the decoded image. Nearest is fastest but blocky; Bilinear is a
good default; Bicubic and Lanczos3 are higher-quality but slower.
[...]
| **Resize mode** | Stretch | Stretch<br/>Letterbox
| How the source image is fitted into the target dimensions.
'Stretch' scales each axis independently, distorting aspect ratio. 'Letterbox'
preserves aspect ratio and pads the remaining border with 'Letterbox pad value'
(applied in normalised output space).
[...]
| **Score activation** | Softmax | Softmax<br/>Sigmoid<br/>None
| Activation applied to raw per-class scores before selecting the
winning class. Softmax = mutually-exclusive classes (SSD/MobileNet-SSD raw
logits). Sigmoid = independent classes (YOLOv5/v8 style). None = the model
already emits probabilities/scores; use raw argmax with the raw score as
confidence.
[...]
| **Score output index** | 0 |
| Zero-based index of the model output tensor that holds
classification scores. The processor slices the concatenated payload from
InvokeTractModel according to the 'tensor.N.bytes' attributes.
[...]
-| Standard Deviation | 255.0 |
| Divisor applied after subtracting 'Mean'. Accepts a single value
(broadcast) or three comma-separated values (per channel). Must be non-zero.
Example: '255.0' to scale u8 pixels into [0.0, 1.0]; '0.229, 0.224, 0.225' for
ImageNet.
[...]
+| **Standard Deviation** | 255.0 |
| Divisor applied after subtracting 'Mean'. Accepts a single value
(broadcast) or three comma-separated values (per channel). Must be non-zero.
Example: '255.0' to scale u8 pixels into [0.0, 1.0]; '0.229, 0.224, 0.225' for
ImageNet.
[...]
| **Target height** | |
| Height in pixels the decoded image is resized to before
normalisation and inference.
[...]
| **Target width** | |
| Width in pixels the decoded image is resized to before
normalisation and inference.
[...]
| **Tensor shape format** | CHW | CHW<br/>HWC
| Memory layout of the tensor fed to the model. CHW
(channels-first) is typical for PyTorch/ONNX detectors. HWC (channels-last)
matches TensorFlow/TFLite. Ignored for Grayscale (always effectively 1xHxW).
[...]
@@ -151,10 +151,10 @@ In the list below, the names of required properties
appear in bold. Any other pr
### Relationships
-| Name | Description
|
-|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| failure | The image could not be decoded, the input tensor could not be
built, the model failed to run, or the model outputs could not be interpreted
as scores + boxes. |
-| success | Inference and post-processing completed. The flow file content is
the original, unchanged image; the detected boxes are written to the configured
output attribute as a JSON array (may be empty). |
+| Name | Description
|
+|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| failure | The image could not be decoded, the input tensor could not be
built, the model failed to run, or the model outputs could not be interpreted
as scores + boxes.
|
+| success | Inference and post-processing completed. The detected boxes are
written as a JSON array (may be empty) to the attribute named by 'Output
attribute name', leaving the flow file content as the original image; if that
property is empty, they replace the flow file content instead. |
### Output Attributes
@@ -174,11 +174,11 @@ Decodes the image from the flow file content, draws each
bounding box supplied v
In the list below, the names of required properties appear in bold. Any other
properties (not in bold) are considered optional. The table also indicates any
default values, and whether a property supports the NiFi Expression Language.
-| Name | Default Value | Allowable Values | Description
|
-|--------------------|---------------------|------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| Bounding boxes | ${enrichment.value} | | JSON array of
bounding boxes to draw onto the image (fields class_id, confidence, x_min,
y_min, x_max, y_max; coordinates normalised to [0,1] against the image).
Typically the attribute produced by an upstream DetectObject or
FilterBoundingBoxes processor.<br/>**Supports Expression Language: true** |
-| Line color | #00FF00 | | Outline color
as a hex string (e.g., '#ff00ff' or '#f0f')
|
-| **Line thickness** | 5 | | Thickness in
pixels of the drawn box outline.
|
+| Name | Default Value | Allowable Values | Description
|
+|--------------------|---------------|------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **Bounding boxes** | | | JSON array of
bounding boxes to draw onto the image (fields class_id, confidence, x_min,
y_min, x_max, y_max; coordinates normalised to [0,1] against the image).
Typically the attribute produced by an upstream DetectObject or
FilterBoundingBoxes processor.<br/>**Supports Expression Language: true** |
+| **Line color** | #00FF00 | | Outline color as a
hex string (e.g., '#ff00ff' or '#f0f')
|
+| **Line thickness** | 5 | | Thickness in pixels
of the drawn box outline.
|
### Relationships
@@ -239,11 +239,11 @@ In the list below, the names of required properties
appear in bold. Any other pr
|-------------------------|---------------|-----------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
[...]
| **Color format** | RGB | RGB<br/>BGR<br/>Grayscale
| Color space of the tensor fed to the model. RGB and BGR produce
three-channel tensors (channel order determined by the format); Grayscale
produces a single-channel luma tensor.
[...]
| **Letterbox pad value** | 0.0 |
| Value written for padding pixels when 'Resize mode' is
'Letterbox'. This is a normalised value (post mean/std), so 0.0 corresponds to
a neutral input for most networks. Ignored when 'Resize mode' is 'Stretch'.
[...]
-| Mean | 0.0 |
| Value subtracted from each pixel before dividing by 'Standard
Deviation'. Accepts either a single value (broadcast to all channels) or three
comma-separated values applied per channel in the order dictated by 'Color
format'. Example: '0.485, 0.456, 0.406' for ImageNet-style RGB normalisation.
[...]
+| **Mean** | 0.0 |
| Value subtracted from each pixel before dividing by 'Standard
Deviation'. Accepts either a single value (broadcast to all channels) or three
comma-separated values applied per channel in the order dictated by 'Color
format'. Example: '0.485, 0.456, 0.406' for ImageNet-style RGB normalisation.
[...]
| **Pixel divisor** | 1.0 |
| Divisor applied to raw u8 pixel values before subtracting 'Mean'
and dividing by 'Standard Deviation'. Defaults to 1.0 (mean/std interpreted in
[0, 255] pixel space, e.g. UltraFace's mean=127, std=128). Set to 255 to bring
pixels into [0.0, 1.0] first so ImageNet-style mean/std values like '0.485,
0.456, 0.406' / '0.229, 0.224, 0.225' can be used directly, matching the
PyTorch / torchvision / ONNX [...]
| **Resize filter** | Bilinear |
Nearest<br/>Bilinear<br/>Bicubic<br/>Lanczos3 | Interpolation filter applied
when resizing the decoded image. Nearest is fastest but blocky; Bilinear is a
good default; Bicubic and Lanczos3 are higher-quality but slower.
[...]
| **Resize mode** | Stretch | Stretch<br/>Letterbox
| How the source image is fitted into the target dimensions.
'Stretch' scales each axis independently, distorting aspect ratio. 'Letterbox'
preserves aspect ratio and pads the remaining border with 'Letterbox pad value'
(applied in normalised output space).
[...]
-| Standard Deviation | 255.0 |
| Divisor applied after subtracting 'Mean'. Accepts a single value
(broadcast) or three comma-separated values (per channel). Must be non-zero.
Example: '255.0' to scale u8 pixels into [0.0, 1.0]; '0.229, 0.224, 0.225' for
ImageNet.
[...]
+| **Standard Deviation** | 255.0 |
| Divisor applied after subtracting 'Mean'. Accepts a single value
(broadcast) or three comma-separated values (per channel). Must be non-zero.
Example: '255.0' to scale u8 pixels into [0.0, 1.0]; '0.229, 0.224, 0.225' for
ImageNet.
[...]
| **Target height** | |
| Height in pixels the decoded image is resized to before
normalisation and inference.
[...]
| **Target width** | |
| Width in pixels the decoded image is resized to before
normalisation and inference.
[...]
| **Tensor shape format** | CHW | CHW<br/>HWC
| Memory layout of the tensor fed to the model. CHW (channels-first)
is typical for PyTorch/ONNX detectors. HWC (channels-last) matches
TensorFlow/TFLite. Ignored for Grayscale (always effectively 1xHxW).
[...]
diff --git
a/minifi_rust/extensions/minifi_tensor/src/low_level_processors/classify_output.rs
b/minifi_rust/extensions/minifi_tensor/src/low_level_processors/classify_output.rs
index 90a2500f1..2d741ae69 100644
---
a/minifi_rust/extensions/minifi_tensor/src/low_level_processors/classify_output.rs
+++
b/minifi_rust/extensions/minifi_tensor/src/low_level_processors/classify_output.rs
@@ -48,7 +48,7 @@ pub(crate) struct LabelsProperty {}
impl PropertySchema for LabelsProperty {
const CONSTRAINT: Option<PropertyConstraints> = None;
- const IS_REQUIRED: bool = false;
+ const IS_REQUIRED: bool = true;
}
impl PropertyType for LabelsProperty {
@@ -199,7 +199,10 @@ impl ClassifyOutput {
Some(Content::Buffer(
serde_json::to_vec(&predictions).route_err_to_failure()?,
)),
- None,
+ Some((
+ MIME_TYPE_ATTR.name.to_string(),
+ "application/json".to_string(),
+ )),
),
Some(output_attr) => (
None,
@@ -211,7 +214,6 @@ impl ClassifyOutput {
};
let mut transformed = TransformedFlowFile::new(&SUCCESS, content)
- .with_attribute(MIME_TYPE_ATTR.name, "application/json")
.with_attribute(CLASS_COUNT_ATTR.name,
predictions.len().to_string());
if let Some(top) = predictions.first() {
@@ -416,10 +418,29 @@ mod tests {
.transform(&context, &mut stream, &MockLogger::new())
.unwrap();
assert_eq!(result.attribute("class.top1.name").unwrap(), "goldfish");
+ assert_eq!(
+ result.attribute(MIME_TYPE_ATTR.name).unwrap(),
+ "application/json"
+ );
let json =
String::from_utf8(result.into_bytes().unwrap().unwrap()).unwrap();
assert!(json.contains("\"class_name\":\"goldfish\""));
}
+ #[test]
+ fn test_output_attr_name() {
+ let processor = make_processor(1, ScoreActivation::None);
+ let scores = vec![0.1f32, 0.9, 0.5];
+ let mut context = context_with_scores(&scores);
+ context
+ .properties
+ .insert(OUTPUT_ATTRIBUTE_NAME.name().to_string(), "something");
+ let mut stream = Cursor::new(build_payload(&scores));
+ let result = processor
+ .transform(&context, &mut stream, &MockLogger::new())
+ .unwrap();
+ assert!(result.attribute(MIME_TYPE_ATTR.name).is_none());
+ }
+
#[test]
fn test_label_offset() {
let mut file = NamedTempFile::new().expect("Failed to create temp
file");
diff --git
a/minifi_rust/extensions/minifi_tensor/src/processors/classify_image/classify_image_def.rs
b/minifi_rust/extensions/minifi_tensor/src/processors/classify_image/classify_image_def.rs
index a7e86c57a..174bdaff4 100644
---
a/minifi_rust/extensions/minifi_tensor/src/processors/classify_image/classify_image_def.rs
+++
b/minifi_rust/extensions/minifi_tensor/src/processors/classify_image/classify_image_def.rs
@@ -32,9 +32,10 @@ pub(crate) const TRACT_MODEL_SERVICE:
Property<TractModelService> = Property::ne
pub(super) const SUCCESS: Relationship = Relationship {
name: "success",
- description: "Inference and post-processing completed. The flow file
content is the original, \
- unchanged image; the classifications are written to the
configured output \
- attribute as a JSON array (may be empty).",
+ description: "Inference and post-processing completed. The classifications
are written as a \
+ JSON array (may be empty) to the attribute named by 'Output
attribute name', \
+ leaving the flow file content as the original image; if that
property is empty, \
+ they replace the flow file content instead.",
};
pub(super) const FAILURE: Relationship = Relationship {
@@ -49,9 +50,10 @@ impl ProcessorDefinition for ClassifyImage {
against the compiled model owned by the referenced TractModelService,
and post-processes \
the score vector (score activation, Top-K selection, confidence
filtering, optional label \
lookup) into predictions. Collapses the ImageToTensor ->
InvokeTractModel -> \
- ClassifyOutput chain into one node. The flow file content is left
unchanged (the original \
- image); the Top-K classifications are written as a JSON array to the
configured output \
- attribute.";
+ ClassifyOutput chain into one node. The Top-K classifications are
emitted as a JSON \
+ array: when 'Output attribute name' is set they are written into that
attribute and \
+ the flow file content is left unchanged (the original image); when it
is left empty they replace \
+ the flow file content instead.";
const INPUT_REQUIREMENT: ProcessorInputRequirement =
ProcessorInputRequirement::Required;
const SUPPORTS_DYNAMIC_PROPERTIES: bool = false;
const SUPPORTS_DYNAMIC_RELATIONSHIPS: bool = false;
diff --git
a/minifi_rust/extensions/minifi_tensor/src/processors/detect_object/detect_object_def.rs
b/minifi_rust/extensions/minifi_tensor/src/processors/detect_object/detect_object_def.rs
index c4e56e9ab..ca17698e3 100644
---
a/minifi_rust/extensions/minifi_tensor/src/processors/detect_object/detect_object_def.rs
+++
b/minifi_rust/extensions/minifi_tensor/src/processors/detect_object/detect_object_def.rs
@@ -32,9 +32,10 @@ pub(crate) const TRACT_MODEL_SERVICE:
Property<TractModelService> = Property::ne
pub(super) const SUCCESS: Relationship = Relationship {
name: "success",
- description: "Inference and post-processing completed. The flow file
content is the original, \
- unchanged image; the detected boxes are written to the
configured output \
- attribute as a JSON array (may be empty).",
+ description: "Inference and post-processing completed. The detected boxes
are written as a \
+ JSON array (may be empty) to the attribute named by 'Output
attribute name', \
+ leaving the flow file content as the original image; if that
property is empty, \
+ they replace the flow file content instead.",
};
pub(super) const FAILURE: Relationship = Relationship {
@@ -64,9 +65,12 @@ impl ProcessorDefinition for DetectObject {
the compiled model owned by the referenced TractModelService, and
post-processes the \
model outputs (score activation, confidence filtering, box decoding,
per-class \
non-maximum suppression) into bounding boxes. Collapses the
ImageToTensor -> \
- InvokeTractModel -> FilterBoundingBoxes chain into one node. The flow
file content is \
- left unchanged (the original image); the detected boxes are written
as a JSON array to \
- the configured output attribute so a downstream DrawBoundingBox can
annotate the image.";
+ InvokeTractModel -> FilterBoundingBoxes chain into one node. \
+ The detected boxes are emitted as a JSON array: when 'Output
attribute name'\
+ is set they are written to that attribute and the \
+ flow file content is left unchanged (the original image), so a
downstream \
+ DrawBoundingBox can annotate it; when it is left empty they replace
the flow file \
+ content instead.";
const INPUT_REQUIREMENT: ProcessorInputRequirement =
ProcessorInputRequirement::Required;
const SUPPORTS_DYNAMIC_PROPERTIES: bool = false;
const SUPPORTS_DYNAMIC_RELATIONSHIPS: bool = false;
diff --git
a/minifi_rust/extensions/minifi_tensor/src/processors/draw_bounding_box.rs
b/minifi_rust/extensions/minifi_tensor/src/processors/draw_bounding_box.rs
index 2b18502c3..0ded6fcf7 100644
--- a/minifi_rust/extensions/minifi_tensor/src/processors/draw_bounding_box.rs
+++ b/minifi_rust/extensions/minifi_tensor/src/processors/draw_bounding_box.rs
@@ -43,7 +43,6 @@ pub(crate) const BOUNDING_BOXES: Property<BoundingBoxes> =
Property::new(
y_min, x_max, y_max; coordinates normalised to [0,1] against the image).
Typically the \
attribute produced by an upstream DetectObject or FilterBoundingBoxes
processor.",
)
-.with_default("${enrichment.value}")
.supports_expression_language();
const LINE_THICKNESS: Property<u32> = Property::new(
@@ -77,7 +76,7 @@ struct LineColor {}
impl PropertySchema for LineColor {
const CONSTRAINT: Option<PropertyConstraints> = None;
- const IS_REQUIRED: bool = false;
+ const IS_REQUIRED: bool = true;
}
impl PropertyType for LineColor {
diff --git a/minifi_rust/extensions/minifi_tensor/src/utils/bounding_box.rs
b/minifi_rust/extensions/minifi_tensor/src/utils/bounding_box.rs
index a74c30c1c..4c134990e 100644
--- a/minifi_rust/extensions/minifi_tensor/src/utils/bounding_box.rs
+++ b/minifi_rust/extensions/minifi_tensor/src/utils/bounding_box.rs
@@ -134,7 +134,7 @@ pub(crate) struct BoundingBoxes {}
impl PropertySchema for BoundingBoxes {
const CONSTRAINT: Option<PropertyConstraints> = None;
- const IS_REQUIRED: bool = false;
+ const IS_REQUIRED: bool = true;
}
impl PropertyType for BoundingBoxes {
diff --git a/minifi_rust/extensions/minifi_tensor/src/utils/per_channel_f32.rs
b/minifi_rust/extensions/minifi_tensor/src/utils/per_channel_f32.rs
index 39f198ad4..ab231e48f 100644
--- a/minifi_rust/extensions/minifi_tensor/src/utils/per_channel_f32.rs
+++ b/minifi_rust/extensions/minifi_tensor/src/utils/per_channel_f32.rs
@@ -42,7 +42,7 @@ impl PerChannelF32 {
impl PropertySchema for PerChannelF32 {
const CONSTRAINT: Option<PropertyConstraints> = None;
- const IS_REQUIRED: bool = false;
+ const IS_REQUIRED: bool = true;
}
impl PropertyType for PerChannelF32 {