Introduction

INFINIWORKFLOW is a node-based platform for building AI, ML, and Computer Vision pipelines, with real-time support for sensor acquisition and device control.

User Interface Elements

INFINIWORKFLOW runs entirely in your browser. Its main UI components are:

HUB

The HUB portal provides a comprehensive overview of the system's capabilities, hardware compatibility, and the latest software advancements. To open the information overlay, click the HUB icon located in the toolbox. The following functions are available at the HUB:

The App Menu is a floating toolbar docked to the top of the canvas, providing the following functionality:

Example: the real App Menu toolbar (a floating bar docked to the top of the canvas - hover peeks it, pin it open with the pin icon on the left)
| |

Hover any icon above to see its name - the same tooltip behavior as the real toolbar. Gold icons open AI features, red icons are destructive (New Workflow/Exit), and the underlined icons on the left each expand into their own popout menu (File, Edit, Workflow Graph, Customize, Settings, Windows, Performance, Help) - listed in full below.

Hide and Show the Toolbox

Pauses all the selected playable nodes which is useful if you are tracking and want to position the tracker marker

Toolbox

The Toolbox is where you add new tools to your flowgraph as nodes.

The first tab shows every tool; the remaining tabs each show a subset, such as tools related to Computer Vision or ML. Hover over a tab icon to see a tooltip with its category name. Once you've selected a category tab, you can further narrow the list by typing keywords into the search field - useful for quickly finding a specific tool to insert into your workflow.

Example: the Toolbox docked at the bottom of the canvas - category tabs, search, and a grid of draggable tool tiles
Canny Edge
Find Contours
Movie Reader
YOLO8 Classification
ONNX Runtime
Widget: Slider

Tool tile colors indicate language: purple = C++, blue = Python, green = CUDA, orange = OpenCL, pink = OpenGL, gray = Widget. The highlighted tile shows a hover/selected state.

Toolbox Gestures

Hovering over a tool shows a tooltip describing it. You can insert a tool into the workflow using any of the following gestures:

Toolbox Layouts

Infiniworkflow has several hundred nodes available, which allows for many possibilities but also can be daunting for new users or can stand in the way of users who are only looking to build a specific application (if you are building a Data Science workflow, you probably don't need to see the many Color Correction nodes that are available). As such, Layouts have been added as a feature for controlling which categories and nodes show up in your Toolbox. They are straightforward to use, but by no means necessary to learn about if you do not wish to change how your Toolbox appears, so you may skip this section and not lose any critical information.

To begin changing how the categories / nodes appear within your Layout's Toolbox, click on the Layouts button and then click on the Layout you wish to change. Now that you're in, you may begin moving both categories and nodes as you like. The following operations are possible:

If you are unhappy with your Layout and want to start over, simply go to the Settings button and click on the "Reset Layout" button. Alternatively, you may delete the Layout all together by clicking on the "Delete Layout" button within Settings. NOTE: Make sure that you are IN the Layout that you want to reset / delete, or you may end up resetting / deleting the wrong Layout! Do this by clicking on the desired Layout after clicking the Layouts button before making any changes.

Flowgraph

The flowgraph is where you construct your workflow, which comprises Nodes and Edges. Nodes represent functions that take input and generate outputs. You create nodes by dragging tools into your workflow from the Toolbox. A node's inputs and outputs have 'ports', which are where edges connect. An edge connects the output port of an upstream node to the input port of a downstream node. Any input port left unconnected can instead be set to a specific value using the Parameter Editor. A node's color indicates its execution language:

C++ Nodes (can be executed on GPU or CPU)
Python Nodes (can be executed on GPU or CPU)
Cuda Kernels (always executed on the GPU)
Widget nodes (executed on the CPU)

The flowgraph has the following components:

Edge Gestures

There are a few exceptions to allow different types to be connected to each other. For example, the image2D type, which represents a 2D image in system memory, can be connected to a type cuda2D, a 2D image in GPU memory and vice-versa. The exceptions are as follows:

Output Type Input Type
* Any type
Any type *
image2D cuda2D
cuda2D image2D
double, int, bool or numeric double, int, bool or numeric
double, int, bool or numeric double, int, bool or numeric
numeric2 double2, int2
double2, int2 numeric2
numeric3 double3, int3
double3, int3 numeric3
torch.nn.Module torchvision.model
torchvision.model torch.nn.Module

Removing an edge disconnects the output of an upstream node from the input of a downstream node. In this example, we no longer want Yolo Classification run on the output of the Movie Reader. Hover over the edge - the cursor changes to show it can be deleted - then click the edge to delete it.

Node Gestures

Port Gestures

Viewport Gestures

Node Context Menu

Clicking the left mouse button over the node brings up the node context menu and also selects the node

Inspect and adjust

Node attribute

Performance

ML functions are available when ML nodes are selected

Experimental

Selection

When you bring up the context menu without a node selected, the flowgraphs viewport functions are shown:

Parameter Editor

The Parameter Editor allows you to edit the parameters of the currently edited node

Example: editing a YOLO8 Classification node
Ultralytics YOLO8 Classification
Main
Advanced
person × car × + add class...
Reset All
Cancel
OK

The dialog is laid out as the tool icon and the name of the node being edited, followed by the list of that node's input parameters, and finally the dialog buttons. Clicking the node's name opens a webpage with the tool's full description. Only inputs that aren't already connected via the flowgraph show up as editable parameters here - a connected input's value comes from its upstream node instead.

Hovering over the parameter will show the description of the parameter:

The dialog buttons allow you to close the dialog - either you can accept the changes made by clicking OK, or reject any changes made to the parameters by clicking Cancel. A button also allows you to Reset All the parameters to the original default tool settings. The UI for each parameter input will be based on the type of the input, but all of them will have a reset icon that allows you to reset that particular parameter input back to its default value. The different types of parameter UI controls are as follows

Viewer

Example: the real Viewer toolbar (hover any icon to see its name)
1:1 | | |

Hover any icon above to see its name. The divider groups are: zoom/inspection, frame playback, wipe compare, color channels & adjustments, and the collapsible More Tools menu (Measurement, Keystone, Stabilize, Multi-View, plus the Path Editor tools).

The viewer allows you to view the outputs of the currently viewed node

The viewer's toolbar includes the following functions:

The viewer, on top of displaying images, has specific UI to display mutli-dimensional data:

Measurement

Keystone

Stabilize

Multi-View

Multi-View compares up to 4 image sources live, in one place - a wipe divider or side-by-side split for 2, a tiled 3-way or 4-way view for 3 or 4. Slot A always tracks whatever you're currently viewing in the main viewer; slots B, C and D are added and removed manually from the Multi-View dialog itself, so browsing to something else in the flowgraph never disturbs a comparison you've already built up. It never permanently adds anything to the flowgraph: opening Multi-View creates a temporary, hidden compare node behind the scenes, and closing Multi-View removes it immediately. Only image outputs can be compared this way (not data frames, tensors, or other non-image views).

Multi-View is only available from the main viewer - it isn't part of the AI Label Studio or Video Segmentation Studio viewing workflow. For comparing camera nodes specifically, see Live Cameras, which sets up a Multi-View comparison of every camera in the workflow in one click.

Live Cameras

Live Cameras, in the floating Toolbox and also under the Windows menu, is a one-click way to see every camera in the current workflow at once. It automates the exact same steps as viewing a node and turning on Multi-View yourself - it doesn't add any special hidden mode of its own - so anything true of Multi-View elsewhere in this manual (up to 4 sources, temporary hidden compare node, image-only) is true here too.

Data frames

Dataframes represent 2D tables and are implemented using the Pandas Python module. The viewer displays the DataFrame as a HTML table. Additional controls allow you to slice a set of the rows and columns, in the example below we slice rows [30-40). The icon allows different views of the table including showing the sliced rows and columns, with red cells represent missing data, a summary description of the statistics of each column, a line chart of the numerical columns and the description of the types of each column:

Numpy Arrays

Numpy represents multidimensional numerical arrays and are implemented using the Numpy Python module. You can set a matrix using the Set Matrix tool. The viewer can display Numpy arrays in a variety of different visualizations where it will select the most useful visualization first and by clicking the allows you to visualize other representations of the arrays. Slicing controls are also available to reduce the tensor to a subset of its numerical data.

Tensors

Tensors represent multi-dimensional numerical arrays and are implemented using the PyTorch Python module. The viewer can display tensors in a variety of different visualizations where it will select the most useful visualization first and by clicking the allows you to visualize other representations of the tensor. Slicing controls are also available to reduce the tensor to a subset of its numerical data.

Beyond displaying images and matrices, INFINIWORKFLOW has specific UI to display one-dimensional audio data:

Project Resolution

The concept of the project resolution is meant to be used for spatial parameters (points and path parameters). These parameters will have defaults in percentages, for example a point parameter could have the deualt of (50%,50%), which corresponds to the center of the project resolution. After nodes are placed down the defaults are converted to pixel coordinates and the user will set pixel coordinates. However, you can change the project resolution and then also select to modify the spatial parameters to also be updated. This allows the user to work in different resolutions but have the workflow adjust to the new resolution if needed (this is also known as working in a "proxy" resolution, typically a lower resolution but then later swith to the full resoultion for final processing.)

Path Editor

The Path Editor allows you to draw, modify, and manage vector-based shapes and paths over the viewer. These tools are primarily used for measurements, defining regions of interest (ROI), or masking.

Creation Tools

Modification & Geometry

Editor Management

Advanced Path Editing

Insert Shape (Polygons & Curves)

The Shape tool is used for creating both sharp-edged polygons and smooth, complex curves.

Vector Brush & Stroke Mode

The Insert Freehand and Insert Lasso tools support an advanced Vector Brush / Stroke Mode. Instead of always generating solid, filled shapes, this mode allows you to draw strokes and outlines of a specific thickness following your hand path.

Selection & Grouping

Managing multiple points is essential for complex adjustments.

Shape Transformation Mode

When you have selected all points in a path (or a specific group of points), the editor enters Shape Mode.

Pro-Tip:

To quickly enter Shape Mode for a single object, you can often double-click a segment of the path to select all connected vertices instantly.

Quick Tips:

Photron High Speed Cameras

INFINICAM and HAWK are high-speed streaming cameras capable of capturing and transferring 1.2-megapixel of image data to PC memory at 1,000fps via USB 3.1. Infiniworkflow, on top of all of its many other functionalities, is designed to be a platform for using INFINICAM(s) and HAWK(s) and saving their footage. There are certain differences between nodes related to INFINICAM/HAWK and most other nodes, so if you will be using an INFINICAM or HAWK, reading through this section is the fastest way to understand everything Infiniworkflow can do with your camera.

1. INFINICAM / HAWK Viewer node:

When an INFINICAM or HAWK is plugged in, a node called "Infinicam" will come up. This node allows you to view the camera feed, and also set the preroll and postroll frames (pre/postroll frames will be discussed later). If multiple cameras are connected, each one will show up as its own node (i.e. "Infinicam", "Infinicam #2", etc). Note that the camera may take a few seconds to open. Also note that this node only allows you to view the feed; saving is done separately.

2. INFINICAM / HAWK Saving nodes:

Infiniworkflow has 2 ways of saving footage for each camera line — "Infinicam Save Movie" and "Infinicam Save Compressed" for INFINICAM cameras, and "Hawk Save Movie" and "Hawk Save Compressed" for HAWK cameras. These saving nodes will come up for each respective camera that is connected to your machine (in other words, if you have 2 INFINICAM cameras connected, "Infinicam Save Movie" and "Infinicam Save Compressed" save footage from the first, and "Infinicam Save Movie #2" and "Infinicam Save Compressed #2" save footage from the second — the same numbering convention applies to HAWK nodes). Note that these saving nodes do not need to be connected to the viewer node itself; all that is required is that the Trigger is clicked.

The "Save Movie" nodes ("Infinicam Save Movie" / "Hawk Save Movie"), upon hitting the Trigger, save footage from the selected camera in any file type (.MP4, .MDAT, etc.) and to any file location. The total number of frames that will be saved when the Trigger is clicked is based on your camera's pre-roll and post-roll number of frames. To explain what these terms mean, consider the following example: you wish to save footage whenever an object falls off a conveyor belt in a factory. You have a workflow that will set a Trigger to True as soon as it detects that an object has just begun to fall off the belt. To understand why objects sometimes fall off the belt, you want to save the 2000 frames of footage from before the moment the object begins falling, as well as 1000 frames of footage after that point for good measure. Thus, you will set your pre-roll to 2000, and your post-roll to 1000. When the Save Movie node is Triggered, a total of 3000 frames will be saved precisely as you want them to.

The "Save Movie" nodes tend to be slower, as they need to compress and decompress data on the fly. The "Save Compressed" nodes ("Infinicam Save Compressed" / "Hawk Save Compressed"), on the other hand, save out compressed images, which means footage gets saved to your computer faster and is more informationally dense (a single 2 second video can be a few hundred megabytes). Whereas the Save Movie nodes allow users to select the Codec and File format, the Save Compressed nodes hardcode both, so 2 files are always returned: a MDAT file of the footage itself and a CIH file of the footage metadata.

Note for all saving nodes: if the Trigger has already been pressed and you wish to stop saving (i.e. save a shorter clip of footage), you can simply click the Trigger again to immediately save out all frames already gathered to your machine.

If you wish to view footage saved from either "Save Compressed" node, use the "Infinicam Movie Reader" node, which reads MDAT/CIH files.

Important note: by default, when a "Save Compressed" node is Triggered, the number of frames saved will equal the camera's preroll plus postroll. However, if you wish to save footage continually, you can click the checkbox in the editing menu for "Constant Saving". When true, you may set the maximum file size for the saved footage. When the node is Triggered, footage will continue to save into the file you created until the maximum file size limit has been reached.

3. INFINICAM/HAWK Trio (3-camera RGB composite) node:

When 3 or more INFINICAM/HAWK devices are connected, additional nodes called "Infinicam Trio" and "Hawk Trio" become available in the catalog (both work identically - INFINICAM and HAWK devices are the same underlying camera pool in Infiniworkflow, so which one you see depends only on which brand name you drag onto the canvas). A Trio node drives three devices as one synchronized unit and packs them into a single 3-channel image - the Left camera becomes the Red channel, Middle becomes Green, and Right becomes Blue. All three cameras share one settings panel (fps, shutter, resolution, expose); there is no way to give the three cameras different acquisition settings, by design.

Which three physical cameras play the roles of Left/Middle/Right is chosen once, in a picker dialog, the moment you drag a Trio node onto the canvas - drag each detected camera tile into a Left/Middle/Right slot, then confirm. This assignment is then locked for the lifetime of that node: to point the node at different cameras, delete it and drag a new Trio node onto the canvas to pick again. This mirrors how a regular Infinicam/Hawk node's device cannot be changed after it is placed either.

Trio nodes require monochrome cameras - a device reporting a color sensor is refused with an error naming that device. The Left camera is automatically the synchronization (genlock) master; Middle and Right automatically slave to it. If the three cameras' frames ever drift out of alignment (a dropped frame, a disconnected cable), the node holds its last good composite and reports a sync-degraded status rather than silently showing a misaligned image.

Besides its main packed-RGB output, a Trio node has a second output called "strip", showing the three source frames laid out side by side (Left | Middle | Right) rather than merged into channels - useful for monitoring what each individual camera sees. This is only computed while something is actually connected to or viewing that output, so leaving it unused costs nothing.

Saving a Trio composite works the same way as a regular Infinicam/Hawk: connect (or simply enable) an "Infinicam Trio Save Movie" or "Hawk Trio Save Movie" node and click its Trigger. It saves the packed RGB composite as a normal color .avi/.mp4 (with the same preroll/postroll behavior described above for the single-camera Save Movie nodes), or as a single still .png image - there is no "Save Compressed"/MDAT equivalent for Trio, since a software-composited RGB frame has no camera-native compressed form to preserve.

If no INFINICAM/HAWK hardware is connected on a development machine, both the regular viewer nodes and the Trio nodes fall back to a simulated noise feed (clearly labeled "SIMULATED" on the image) so workflows remain buildable and testable without hardware attached; this simulated fallback never occurs on a production install.

Utilities

Audio

Audio is represented by a list of numerical intensity values over time and they are implemented using the Numpy Python module. You can get audio using the Read Audio tool for audio files or the Input Audio tool for streaming input through the microphone. The viewers in Audio nodes can display audio arrays in two different ways: a waveform and a spectrogram. It will default to the waveform visualization first, which shows the loudness of the sound at every sample over time. By clicking the , it allows you to cycle through visualizations. The other visualization is a spectrogram, which is a colormap of frequencies over time where colors represent the volume of each frequency in decibels (dB).

Widgets

A set of tools, called Widgets, are available that provide user interface controls directly in the flowgraph

These widgets are an easy way to modify the parameters without having to open the Parameter Editor - you can selectively decide which parameters are important enough to add as widgets to the flowgraph. For example, the following flowgraph has a number of widgets added: a "Filebrowser Widget", a "Selection List Widget" and a "Slider Widget" are added to the flowgraph as well as two "Output Widgets":

You can now modify those controls directly in the flowgraph. You can refine how each widget is shown by editing it in the Parameter Editor and setting its widget attributes. Widget attributes include the name which will show for each widget. Widgets such as Sliders allow you to set their specific attributes such as the minimum, maximum and step value for the Slider widget. All widgets have the common attributes of the name and description (used for tooltips) as well as layouts. The layouts allow you to specify an optional Tab that the widget will be placed in and also the order in which the control will be ordered in the UI (a lower order will allow the control at the top of the layout). An example of the Widget Slider's parameters are as follows:

See the reference section for the full list of Widget Tools

Displays

A set of tools, called Displays, are available that provide viewing displays directly in the flowgraph This allows you to constantly monitor the output of multiple nodes and avoid switching back and for using the Viewer.

See the reference section for the full list of Display Tools

Creating Triggers

You can create triggers to activate certain nodes that require the trigger to start execution. Typically, you can use the various boolean expression - for example, in the workflow below, the number of detected faces is applied to a "Numeric a>b" tool, this will yield a true value whenever the number of faces is greater than a certain amount. The output of this node is a "trigger" that is used to execute the "Text to Speech" node.

Loop Triggers

Loop Triggers is allows you to update a Trigger Variable based on when downstream Python nodes have executed and trigger an upstream Python node. This allows you to do "for" loops as the workflow graph is acyclic - meaning no edges can connect a downstream node to an upstream node, so loops are not allowed. However, with this feature you can make a trigger happen upstream when a downstream node is executed. You can add two new nodes, 'Loop Variable' and 'Loop Trigger':

The Loop Trigger when the source has changed (or you click the next trigegr), will use the referenced Loop Variable and will trigger the output of the Loop Variable. The Loop Variable can be placed upstream and flow back to the Loop Trigger, and thus this forms a loop cycle. You can use Loop triggers to perform simulations which may require multiple passes of the workflow nodes.

Data Science

The Data Science tools are all under the Data Frame category. The implementation is based on Pandas, an open source data analysis and manipulation library. A DataFrame can be loaded with the "Read CSV" or "Read Excel" tools or created programmatically with the "Random Table" tool or converting from numpy or tensors. For many of the tools, they will use "Column" or "Columns" properties representing a choice of a single column or a subset of columns. Some of the tools also have an "arg" property which is a map parameter that allows you to pass in additional key/value pair optional arguments The Key/Value Dialog UI will show the corresponding Pandas function's documentation which is useful to determine the additional parameters you wish to set.

See the reference section for the full list of Data Science Tools

Plotting

A number of tools are available to create charts for DataFrames. These tools are all under the Plot category. Each plot tool has parameters placed into two different tabs: Data and Layout. The Data parameters allow you to set the columns you wish to plot and the Layout parameters allow you to adjust the title of the chart etc.

An subset of the plot tool visualizations are as follows:

See the reference section for the full list of Plot Tools

Machine Learning with scikit-learn

The Machine Learning filters are based using scikit-learn Python module are all under the ML category. Each ML tool has 3 tabs: Train, Hyperparameters and Export. The Train parameters allow you to set the X and Y columns as well as a trigger to start the training. Since training can be slow, a trigger is used to start the process - though when running a grid search, that trigger is generated automatically.

The typical approach to building models involves splitting your training data into test and train splits. The following workflow illustrates the steps involved and the nodes required to implement the training:

The CSV file is read and then a test train split is done, the training table is then passed to the ML model. In this case the "Is Batch" Tool is used to set the "save" parameter which will automatically save the model for any Grid Search. The output of the model is then passed to a model predict and the predicted values can be compared against the ground truth to establish the accuracy of the model. In this scenario, we use a confusion matrix to plot the accuracy of the results. And a ML metric nodes such as "R2 Score" allow you to see the accuracy and it can be further used to initiate a Grid Search.

See the reference section for the full list of ML Tools

Tools

AI

The AI Inference algorithms including using pretrained models tools are all under the AI category. The full list of display tools is as follows:

Audio

The Audio signal processing filters tools are all under the Audio category. The full list of display tools is as follows:

Color

The Image Color Correction filters tools are all under the Color category. The full list of display tools is as follows:

Composite

The Combine and Split Images tools are all under the Composite category. The full list of display tools is as follows:

Database

The Database processing such as reading tables, performing queries and writing to databases tools are all under the Database category. The full list of display tools is as follows:

Datascience

The Datascience filters using the Pandas library tools are all under the Datascience category. The full list of display tools is as follows:

Experimental

The Experimental Tools tools are all under the Experimental category. The full list of display tools is as follows:

ImageProcessing

The Image Processing Filters such as Blurs, Edge Detetors and Morphological Filters tools are all under the Image Processing category. The full list of display tools is as follows:

Grayscale

The Grayscale Filters that create single channel images tools are all under the Grayscale category. The full list of display tools is as follows:

Inputs

The Source Inputs such as Webcameras or Reading Movies tools are all under the Inputs category. The full list of display tools is as follows:

Logic

The Logical functions for conditional processing, useful to create triggers tools are all under the Logic category. The full list of display tools is as follows:

Math

The Mathematical and Scientific Operators tools are all under the Math category. The full list of display tools is as follows:

Matrix

The Matrix operations using numpy arrays tools are all under the Matrix category. The full list of display tools is as follows:

ML

The Machine Learning filters based using scikit-learn tools are all under the ML category. The full list of display tools is as follows:

Outputs

The Display tools that allow you to visualize directly in the flowgraph tools are all under the Outputs category. The full list of display tools is as follows:

Photron

The Photron Camera and Processing Tools tools are all under the Photron category. The full list of display tools is as follows:

Plot

The Plotting tools using Matplotlib tools are all under the Plot category. The full list of display tools is as follows:

Pytorch

The PyTorch deep learning for building ML models tools are all under the Pytorch category. The full list of display tools is as follows:

Rendering

The 3D tools to create 3D scenes and render tools are all under the Rendering category. The full list of display tools is as follows:

Statistics

The Image Statistics tools such as mean, median and RMSE tools are all under the Statistics category. The full list of display tools is as follows:

String

The String tools such as string concatentation tools are all under the String category. The full list of display tools is as follows:

Tracking

The Tracking features in images tools are all under the Tracking category. The full list of display tools is as follows:

Transform

The Image Transformation tools tools are all under the Transform category. The full list of display tools is as follows:

Triggers

The Triggers tools which are useful to create signals for control tools are all under the Triggers category. You can create triggers to activate certain nodes that require a trigger to execute - review the section Creating Triggers. The full list of display tools is as follows:

Utilities

The Python Utility tools tools are all under the Utilities category. The full list of display tools is as follows:

Verticals

The Industry-specific tools built from the verticals proposal review (docs/verticals_todo_analysis.md): agriculture, drones, factory automation, infrastructure, logistics, maintenance, medical, quality inspection, R&D, robotics, safety management, security, smart city, sports analytics, startups, and teaching. Each node's tags list which vertical(s) it belongs to. tools are all under the Verticals category. The full list of display tools is as follows:

Widgets

The User Interface Widgets which can be used for Publishing a simplified UI tools are all under the Widgets category. The full list of display tools is as follows:

System Performance

The "System Performance" tool can be used to report performance metrics of your workflow. You can add it to your workflow and it will output a table of counters that will refresh regularly to show the performance for each node. The output table format is described below:

Column Description
name Name of the node
Work(ms) Average time in milliseconds to process one frame
#Wait Number of times since last update the node waited because inputs were not ready or hadn't changed
#Render Number of times since last update the node executed
Host to Host(MB) Amount of System CPU Host memory copied in megabytes
Host to Device(MB) Amount of System CPU Host memory uploaded to the GPU memory in megabytes
Device to Host(MB) Amount of GPU memory to the System CPU Host memory in megabytes
Device to Device(MB) Amount of GPU memory copied in megabytes
Peer to Peer(MB) Amount of GPU memory in megabytes copied between different GPUs when multiple GPU are available on the system

GUI Designer & Code Generation

The GUI Designer compiles your workflow into a standalone application - a generated C++ or Python program with its own window, viewer, and parameter sidebar - instead of running inside INFINIWORKFLOW itself. It's opened from the same CodeGen entry point used to export OFX/PFV4 plugins and other generated-code targets. For the full walkthrough (Canvas, Views, Features, Style, and Build tabs, plus generating and running the output) see the dedicated CodeGen & GUI Designer guide.

Browser

Example: the Browser's icon view (root folder select, search, view toggles, and a folder/file grid)
$ / demos / Image Processing
..
Verticals
Contours.json
AI_Welding.json
Color_Grade.json
Live_Camera.json

The Browser provides a sophisticated interface for managing, previewing, and selecting your workflows and assets.

1. Navigating the File System

The file browser manages files located in the ${assets}, ${demos}, and ${downloads} folders. Use the Root Folder Select dropdown at the top-left to toggle between these primary storage locations.

Breadcrumb Navigation:

The path bar below the header allows you to jump back to any parent directory by clicking on the folder names.
Example: $ / demos / Verticals

Custom Path Mapping:

You can define additional directory paths as prefixes using the -path argument when launching the application.
Example: ..\python.exe app.pyc -path "captures=C:\Users\imagi\CapturesFolder;media=C:\media"

2. View Modes & Searching

Customize your browsing experience using the icons in the top-right toolbar:

3. Advanced Preview & Training Overlays

When selecting a .json workflow, the browser provides an integrated preview window:

4. Importing and Exporting

The system validates your hardware against the workflow requirements.

Note: If the requirement text turns red, your current system is missing the necessary GPU nodes (CUDA/PyTorch) required to run the selected workflow.

Customize Node

Hide or show the inputs and outputs for a selected node. This feature allows you to simplify the workflow to focus on the most relevant inputs and outputs. The Customize menu is also a concise way of seeing all descriptions for each input/output in one place. The following cutomizations are available in each node:

Grouping

Grouping lets you take a set of connected nodes and combine them into a single compound group node. Grouping reduces the visual complexity of your flowgraph, and you can go further and export a group node as a fully-fledged tool of its own.

See also the section on Customize Nodes which in combination with Grouping allows you to create customized group nodes.

Profile

Profile is available from the toolbar's Performance menu. It measures each node's execution performance and briefly shows a colored FPS speed-dial badge on every active node (green/yellow/red for fast/medium/slow), fading out automatically after a few seconds. It has no effect on performance when not in use.

Synchronize

Synchronize is available from the toolbar's Performance menu when the selected node has 2 or more connected inputs (moved here from the node's right-click context menu, and renamed from "Balance Inputs"). Every node runs on its own free-running thread, so two branches feeding the same node can drift out of sync - one branch might be 3 nodes deep and slower to update than a branch feeding straight from the camera. This opens the Synchronize dialog:

The inserted cv.delay_balance nodes are ordinary nodes - you can select one afterward and hand-tune its delay_ms parameter in the Parameter Editor if needed. It's a time-based sample-and-hold (holds one frame, only refreshing it once real wall-clock time has actually elapsed), not a frame-count buffer, since a branch's own update count isn't a reliable stand-in for elapsed time. This compensation only makes sense while the graph is genuinely free-running live/interactive, so it is automatically bypassed (acts as a pass-through) during export and other batch/composite rendering, and during Stabilization frame tracking.

Thread Control

Merge Threads and Split Threads are available from the toolbar's Performance menu (moved here from the node's right-click context menu). By default each C++ node is executed in a different CPU thread for automatic pipeline acceleration, however, there may be circumstances where you want to finely control the order of stream processing:

Hyperparameters

You can set the hyperparameters using the node context menu and selecting 'Hyperparameters'. This brings up a dialog that allows you to select each input parameter and also set the range of values you want to have as part of the Grid Search. The dialog also includes the documentation for the model including the values expected for each hyperparameter argument.

Grid Search

Once you have created a ML model using the ML Toolsyou have refined your 'Hyperparameters' then you can start a Grid Search on a metric node you wish to maximize or minimize such as the "R2 Score" ML tool. Select the metric node and then bring up the context menu and select 'Grid Search':.

You can also click on the Import link to load the assets created during the Grid Search. Each ML model tool allows you to save the model to a file, by default models will not be saved but it is recommended whenever you have complex models that take time to execute. A common practice when doing a Grid Search is to connect the "Is Batch Tool" to the "save" input parameter of the model - this will always be true when a Grid Search is being done in the background batch process - thus, all the models will be saved during the Grid Search process. The import will then allow you to copy the model into your workflow folder:

Create Macro

When building models using the Torch nodes, the neural networks can get large with multiple nodes to generate the entire neural network. You can create a macro to create a tool that replaces all the nodes with a new tool which can be further used in the future and promotes sharing of models. To create a macro, select the node in your flowgraph that is a "Sequential" Torch Tool , then show the context menu for the node and select 'Create Macro'. The dialog allows you to name and set optional notes that will be associated with this new tool.

PyTorch Deep Learning

PyTorch is an open source machine learning framework that is excellent in performing Deep Learning.

Tensor Manipulation & Conversion

You can find the properties of a tensor by using nodes such as Size, Dimension, Mean, Sum, Standard Deviation, and more. Further, you can combine two or more tensors together via either basic arithmetic (add, subtract, multiply, divide, etc.) or concatenation (concatenate, horizontal stack, vertical stack, etc.).

Additionally, you can convert tensors to and from DataFrames, NumpyArrays, and Images.

Tensor Default Types

In PyTorch, a tensor can be one of many data types. In Infiniworkflow, all tensors are of data type torch.float32 by default (as this is the standard default within PyTorch as well). However, if you wish to change the data type of a tensor, simply drag in a Set Default Type node into the workflow and select one of 4 data types: torch.float32, torch.float64, torch.float16, and torch.bfloat16. This will change the data type of ALL tensors within the workflow. Note that this node doesn’t need to be connected to any other node to work; simply having it somewhere within the workflow is enough.

Neural Networks

Neural Networks in Infiniworkflow can be Trained, Tested, and finally exported to a custom AI Inference node or exported to ONNX. The following sections will break down how to create a neural network, along with bringing in custom datasets and creating your own Inference Macros based on the neural nets you create.

Neural Networks: Regression, Classification, & Segmentation

The steps for creating a Neural Network, whether that be for Regression, Classification, or Segmentation, are more or less the same. The following section will describe in detail how to create a Neural Network for Regression, but most all steps can be copied for Classification or Segmentation. Exceptions and differences to note for creating Classification or Segmentation Neural Networks will be detailed at the end of this section.

To begin regression training (or any kind of training for that matter), we need 4 key inputs: a Neural Network Model, an Optimizer function, a Loss/Criterion Function, and the Data that the model will train on.

The Sequential node performs two actions behind the scenes. Firstly, it combines all machine learning modules that are provided as inputs (including nodes such as Linear, ReLU, Conv2D, MaxPooling2D, LogSoftmax, etc.) into a PyTorch Sequential container; to adjust the amount of input modules the Sequential node takes in, simply right-click on the Sequential node and click “Add Input” or “Remove Input”. Then, the Sequential node takes the Sequential Container and creates a neural network model out of it, with a base class of torch.nn.Module. The output of the Sequential node will thus be the “model” input of the Regression Train node.

Several optimizer functions are included in InfiniWorkflow. Most are intuitive (simply set the Neural Network Model as an input, set the Learning Rate and Weight Decay as needed, then set the output of the Optimizer node as an input to Regression Train), but the Per Parameter Optimizer is easy to misunderstand. The Per Parameter Optimizer node only works in tandem with another Optimizer node (such as Adam Optimizer), so make sure to connect the output of Per Parameter Optimizer as an input to the standard Optimizer node.

Using the Per Parameter Optimizer, specify the individual penalization weights you wish to set for specific parameter groups from your model; note that, if you wanted, you could set an individual penalization weight for each of your model’s parameter groups, but you would need to have a Per Parameter Optimizer node for each of these weights (additionally, you would need to Add Inputs to your standard Optimizer like an Adam Optimizer, and then feed each of your Per Parameter Optimizer nodes into your standard Optimizer). Any parameter groups that are not explicitly specified in any Per Parameter Optimizer nodes will take on the weights specified by the standard Optimizer node.

The output of the standard Optimizers is a torch.optim. Connect this as an input to the Regression Train node.

Several loss functions are included in InfiniWorkflow. Simply connect the one you would like to use as input to Regression Train.

In order to perform Regression, you need clean, numerical data. Assuming that your data is viable, set it as the input to the Train Test Split node. This will allow you to split data into Training data and Testing data. Set the Training data as an input to the Regression Train node.

Edit the Regression Train node and hit the Trigger button to initiate training. You can see the status of the training in real-time by hitting the [Render Status] icon in the application menu. If at any point you want to stop training, simply hit the Abort button within the Render Status Console. If you would like to save the output model once training is complete, click the “save state dict” box to enable saving, and specify where on your local machine you would like the output to be saved to.

With training complete, you can now begin testing your data, which you can do in 2 main ways. The first way is to have a Regression Test node in the same workflow as your Training, and connect the nodes appropriately. The second way is to use a Load Torch Model node, which you can only do if you saved the training output model to your local machine. Note that if you do want to use the Load Torch Model, you need to hit the Trigger in order to bring the data in from your local machine into Infiniworkflow. Furthermore, if you use this method you can have your training and testing in different workflows entirely. However, you would need to either recreate your model entirely (i.e. the Sequential node and all modules that feed into it in your Training workflow), or alternatively create a Macro on the Sequential node in the Training workflow such that the Macro can then be instantly brought into your Testing workflow (and any other workflow you want).

Your training and testing is now complete. The same steps can be repeated for performing Classification or Segmentation, with the biggest exception being the way that the datasets for Classification or Segmentation will appear in Infiniworkflow. An example from the CIFAR10 Dataset can be seen below. View and edit the node and set the “train” input to either Train, Test, or Validate (if Validate is an option).

Below is an example of a training workflow for a Convolutional Neural Network that performs Classification on the MNIST Dataset. Note the similarities between this and the Regression example seen above, with the principal exception being the number of layers that are fed into the Sequential node.

If you wish to create a Convolutional Neural Network (like the one depicted above) but do not want to immediately attempt creating the neural net from scratch, you can use the Convolutional Neural Net node instead to rapidly prototype your desired neural net.

The first three inputs relate to information on the input image data that this CNN will be trained on. The fourth input is how many classes the CNN will be trained to identify. All CNNs are composed of various convolution cycles followed by various fully connected layers. Since this node is meant for rapid prototyping, what is within each of these layers is already set. Each convolution layer is composed of a Convolution 2D, ReLU, and Max Pooling 2D node; each fully connected layer is composed of a Linear and ReLU node, apart from the last fully connected layer, which only has a Linear node. A Flatten node separates the convolution layers from the fully connected layers. Specifications for kernel size can be set in the convolution kernel size and pooling kernel size inputs. The final input is a boolean of whether the CNN ends with a LogSoftmax node at the end. Once again, this node is meant for primitive prototyping, and therefore is not fully robust; each fully connected layer only halves the number of filters until it gets to the desired number of classes the dataset identifies.

Datasets In INFINIWORKFLOW

A few common datasets are already implemented in Infiniworkflow for classification and segmentation. These include CIFAR10, MNIST, FashionMNIST, and Cityscapes.

Bringing in custom datasets can be done in one of two ways. The first is via the Generic Dataset node; simply specify the naming convention of your inputs and outputs (X and Y), list all the classes, set the directory of where the dataset is coming from on your local machine, and set a colormap if one exists (for the purpose of segmentation).

The second (and probably more useful) approach is to create a plugin for your desired dataset. Refer to the Customizing Tools section on how to do so.

Create AI Inference Tools Using Your ML Models

Once a model has been trained, users can then take their model and immediately begin using them within Infiniworkflow as a custom node for AI Inference. These nodes are called Inference Tools. (Alternatively, after a model is trained, the model and its weights can be exported to ONNX, a popular machine learning framework, using the Convert To Onnx node.)

To create an Inference Tool, simply right-click and select “Create Inference Tool” after your model has been trained. NOTE: The “Create Inference Tool” option will only appear under a Training Node (i.e. any node that is capable of training a model) after the model has been trained, not before.

Fill in the name of your Tool and any notes associated with it, and hit “Ok”. A prompt should inform you that “New tool has been added”, one which you can find in the toolbox alongside your other nodes. This node will now be able to perform AI Inference using the machine learning model you created and trained.

3D Rendering for Synthetic Rendering

Pyrender is a Python library for physically-based rendering and visualization and useful for Synthetic Rendering.

Basic Object Types in Pyrender

There are three primary object types to know to render a Scene; these are Meshes, Lights, and Cameras.

A Mesh node is basically a wrapper of any number of primitive types. These primitive types represent the physical geometry that can be drawn to the screen. Infiniworkflow allows users to load meshes from existing Trimesh objects. In the assets folder, ensure all necessary files (including the object file, material file, and UV file) are included in order for the mesh to appear correctly when brought into a Scene, as seen below.

The output of a Mesh node is a 3DNode (in Pyrender, “Node” is the name of one of the most commonly-used classes when creating a Scene; in order to avoid confusion between Pyrender Nodes and Infiniworkflow’s Nodes, we have elected to denote Pyrender Nodes as a “3DNode”).

In addition to Meshes that come from existing Trimesh objects, you can also create your own basic 3D objects from scratch using the Trimesh Creator nodes. These basic objects include boxes, capsules, cones, icospheres, and toruses. The output of each of these Trimesh Creator nodes (such as “Trimesh Box” or “Trimesh Capsule”) is a 3DNode.

Pyrender supports 3 types of Light: PointLight, SpotLight, and DirectionalLight. The output of any of these 3 Light nodes is a 3DNode.

Pyrender supports 3 Camera types: PerspectiveCamera, IntrinsicsCamera, and OrthogonalCamera. The output of any of these 3 Camera nodes is a Camera (NOT a 3D Node).

Creating a Scene using Pyrender

To begin creating a Scene, bring in a Render Scene node from the Pyrender toolbox (marked with a 3D icon). The camera that you choose to view your scene with is the first input to the Render Scene node. The final input is for any 3DNodes you want to be present in your scene (i.e. Lights, Meshes, etc.); the Render Scene node allows users to add as many 3DNode inputs as they wish. The output of the Render Scene node is a Color (or Default) viewer, Depth viewer, and Segmentation viewer. Each of these viewers will be explained in further detail below.

If you have been following these steps so far, it is likely that your scene does not show anything. This is because you need to position your Camera and your 3DNodes where you want them. To do this, use a Transformation Matrix node or a LookAt Matrix (generally Transformation Matrices are used for nodes that output a 3DNode and LookAt Matrices are used for nodes that output a Camera, but any of these matrix nodes could be used in practice). Your final workflow might look something like this:

The following is a description of each of the three output views from the Render Scene node:

YOLOX

YOLOX is a version of the computer vision object detection model YOLO (You Only Look Once) that is better for fine-tuning.

YOLOX Train

Training a pretrained YOLOX model on custom data requires a dataset as well as some hyperparameters. YOLOX Train Custom Data

The image dataset must be in COCO or VOC format and labeled using Labelme or CVAT. The YOLOX Train node takes in the COCO/VOC dataset directory, train annotation/labels JSON, and validation annotation/labels JSON.

The hyperparameters include image size (416x416 for YOLOX light models, 640x640 for standard YOLOX models), the number of unique classes in the dataset, and the filepath to the checkpoint or pretrained PyTorch (.pth) model.

The experiment (exp) file contains all the other hyperparameters that can be adjusted, with args exposing a select few for ease of use.

The name and output directory determine the name of the fine-tuned model (.onnx) and the output directory where the log data is written to, as seen below:

The YOLOX Train node outputs a model that is trained on the input dataset, so it can classify things outside of the 80 COCO classes that it is originally trained on, like manholes.

Tensorboard Visualization

Tensorboard is a web-based visualization tool for tracking machine learning training and validation errors.

It simply takes in the output directory of an ML training process and a localhost port to be hosted on.

If port is 6006, then triggering the node and opening localhost:6006 will show graphs like these updating live as the model trains:

YOLOX Inference

ONNXRuntime is a high-performance engine tool for ONNX models.

INFINIWORKFLOW features an general-purpose ONNXRuntime node as well as a YoloxOnnxRuntime node.

Fortunately, the YOLOX Train node outputs an .onnx model, so the YoloxOnnxRuntime node can be used.

The relevant inputs for running inference on YOLOX are the model input, the list of class labels if they are not the standard COCO classes, and the input size (416x416 for YOLOX light models, 640x640 for standard YOLOX models).

The YoloxOnnxRuntime node outputs a preview of the detected objects as well as an output matrix.

Network Manager

Network Manager lets you move part of your workflow onto a different process on the same machine, or a different machine on the network entirely - useful for spreading heavy processing across more hardware, or offloading GPU-bound nodes onto a dedicated machine. It is opened from the toolbox's Performance menu's Network Manager button.

Picking nodes and a target

The dialog opens on a schematic view of your workflow (any nodes already selected on the live canvas are seeded into the selection). Click a node, or drag a box to select several, to build the set of nodes to send - the selection must form a single, contiguous region of the graph (one boundary edge in, one boundary edge out). A Profile button on this screen runs a short live FPS pass over the schematic so you can see which nodes are slow before deciding what to send, without committing to anything yet. The sidebar lists known peers (discovered automatically via UDP beacon from other INFINIWORKFLOW instances started with -distributed-listen) to pick as the send target, plus the CUDA Device on the target that will run the selected nodes.

Example: picking a peer and device before sending a selection
Network Manager
(workflow schematic - click nodes to select)
This machine
127.0.0.1
GPU-WORKSTATION
192.168.1.42
Cancel
Next

Suggested distribution targets

Once a Profile pass has produced real timing data for the open workflow, a Suggest button appears alongside the schematic. It opens a small ranked list of candidate selections, each pre-checked against every rule the dialog itself would enforce - so anything offered here is guaranteed sendable. Candidates form a ladder from a single node up to a handful of nodes: the first entry is just the single slowest node in the workflow, the next adds whichever directly-adjacent node is next slowest, and so on - always one contiguous region, never a scattered pick. Each row shows a small preview of its nodes, the estimated time saved, and the estimated data cut across its new boundary. Already-distributed (bridge) nodes and display/viewer nodes are never offered, since neither can usefully be sent to a peer. Click Use this selection on any row to close the list and carry that candidate straight into the normal node selection, ready to pick a peer and device as usual.

Every image output the selection exposes at its boundary gets a real port on the local Distributed Source node - including one that isn't wired to anything yet, so there's always somewhere to connect something new later without having to undistribute first. A CUDA-accelerated node's output is exposed locally as a plain image type rather than a GPU buffer either way, since the actual pixels always cross the network as ordinary data - GPU memory itself is never shared between machines (or processes). Double-clicking the Distributed Source node shows its current output live, the same as any other image-producing node.

Asset checklist

Clicking Next builds a manifest of the files referenced by the selected nodes' file inputs (models, LUTs, media, etc). For a remote target, each entry defaults to checked unless the target already appears to have a matching copy (shown with a "target already has this" note and left unchecked) - uncheck any others you don't want copied, then click Copy to actually transfer them. For a local target (this machine, whether in-thread or a separate process), the same list is shown as read-only "Referenced Files" instead - nothing is actually copied, since a local target already reads every file from the exact same filesystem the checklist itself was built from; just click Next to continue. Nodes that may not relocate safely are flagged here as warnings either way. If nothing is referenced at all, this step is skipped automatically.

Sending and start-gated execution

Clicking Copy transfers the checked assets to the target with a live progress bar (cancellable). Once the copy finishes - or immediately, if nothing needed to be copied - the dialog reaches a Ready step; nothing has been sent to the graph yet. Only when you click Proceed do the selected nodes actually get replaced with a pair of bridge nodes, Distributed Sink and Distributed Source, and the job starts: the Sink sends data out from your system and the Source receives the processed data back in. This lets you review the asset checklist and back out before anything changes your workflow.

Example: the three steps of the sidebar, left to right - the asset checklist, the copy in progress, and the final Ready confirmation
Assets to copy
Files referenced by the selected nodes' file inputs. Uncheck any you don't want copied.
${assets}/yolo8/yolov8n.onnx
6.23 MB
${assets}/yolo5/classes.txt
0.01 MB target already has this
Copy
Copying assets...
1 / 2 files - 64%
Cancel
Ready
Assets copied. 1 file(s). Clicking Proceed creates the distributed group and starts the job immediately.
Proceed

Running more than one job at once

Multiple distributed jobs can run at the same time. A local target (this machine, used to test distribution without a real second machine) allows any number of concurrent jobs; each distinct remote peer is capped at one job at a time, but different peers can each run their own job concurrently. If a job's selection borders a node that's already part of another active job's boundary, the connection is simply redirected to that other job's live bridge port when needed - nothing is rejected or dropped.

Monitoring running jobs

While one or more jobs are active, reopening the dialog opens on a job picker: a tile per job with its target and status, plus per-job Resume/Delete buttons and Resume All/Delete All shortcuts. Picking a tile shows that job's live status table (refreshed every couple of seconds) with each bridge's role, target, health, frame count and what data it's carrying. Health is derived from a per-tick heartbeat: Connected while frames have arrived recently, Stalled if too much time has passed since the last one, or Waiting.../Not connected before a connection is established. Click Delete (Undistribute) to tear a job down and restore its original nodes.

Example: the job picker, with a healthy local job and a remote job that needs resuming
Network Manager
2 distributed job(s) found in this workflow. Click a job to open it, or use its Resume/Delete directly.
Canny + Find Contours
127.0.0.1
Sink + SourceConnected
Resume
Delete
YOLO Detect
192.168.1.42
Sink + SourceNot connected
Needs resume
Resume
Delete
Delete All
Resume All (1)
Example: the live status cards shown after picking the "YOLO Detect" job tile above - one card per bridge
Distributed Sink
RoleSink (sends data out)
Target192.168.1.42
HealthNot connected
Frames-
Carryingsource, confidenceThreshold
Distributed Source
RoleSource (receives data in)
Target192.168.1.42
HealthNot connected
Frames-
Carryingout, numDetects

Resuming after a restart

A distributed job's bridge nodes are saved as part of the workflow, so the job survives closing and reopening the app (or loading a saved workflow) - but the underlying connection itself is not, so it needs to be told to reconnect. A group node whose job needs resuming shows a pulsing highlight on the flowgraph so it's easy to spot; opening the Distributed Rendering dialog shows a banner with a Resume button per job (or Resume All for every job at once) to reconnect it.

Render to Clip

Render to Clip captures one node's output(s) straight to disk - video, or a CSV for a numeric/matrix value - useful for "freezing" an expensive or slow part of a workflow (a detector, an optical-flow pass, anything GPU-heavy) into plain files you can play back or read back instantly instead of recomputing every time. It's opened from the same Network Manager dialog, as one of two mutually-exclusive modes on the node-selection step: Stream (the dialog's normal continuous distribute/streaming behavior) or Render (this feature). Only one mode is ever active, and which ones are even selectable depends on the current selection - Render requires selecting exactly one node, so it's disabled the moment more than one is selected; Stream stays available for both single- and multi-node selections (whichever ones are valid for it in the first place - the same rules as always).

Selecting a node and its outputs

Unlike a normal distribute selection, Render always takes exactly one node - the one whose output(s) you want recorded. Everything feeding it is discovered automatically by walking the graph backwards from that node, so there's no need to also select its sources by hand. Once a single node is selected and Render is chosen, a picker appears listing every capturable output on that node - image/CUDA outputs record to a video file (with a Format/Codec choice per output), numeric (double/int) outputs record to a single-column CSV, and matrix2D outputs record to a CSV padded out to the largest matrix seen across the recording. Only the first image/CUDA output is checked by default (or the first output of any kind, if the node has no image output at all) - check or uncheck any others you also want captured, and edit each one's filename if you don't want the auto-generated one. A Save to field (with a folder browse button) lets you pick a destination other than the default clip_renders subfolder under your project's assets. Set a start/end frame range, then click Next to proceed - exactly like Stream, Render still goes through peer selection and (for a remote target) asset copying before the export actually starts.

A local Render always runs in a separate INFINIWORKFLOW process, never sharing this session's own live graph or threads - there's no "run in this session" choice the way a plain distribute job has, since interrupting your own interactive session to record a clip would defeat the point. Remote targets work the same way they do for Stream: pick a peer, and the export runs there instead.

Progress is shown live as the export proceeds, all the way up to 100% - not just a spinner - and the job appears as its own tile in the same picker as ordinary distribute and script jobs, with the usual Cancel option while it's running.

Replace, Keep, or Just Keep Files

Once the export finishes, a dialog asks what to do with the recorded outputs - nothing is applied to the graph automatically. Click a card to see what it does, then Confirm:

Either way, a reader node added by Replace or Keep is named after its own output file rather than the generic tool name, so several added at once (one per captured output) are still easy to tell apart on the canvas.

If you close the dialog without choosing, the job stays available - open its tile again from the Distributed Rendering picker to make the same choice later; the exported files are on disk either way, regardless of what you eventually pick.

Remote Script Execution

Remote Script Execution is a separate, lighter entry point from Network Manager above - opened from its own Remote Script Execution button in the Windows menu - for simply running a Python script on this machine or a peer, without touching your workflow's nodes at all.

Opening it browses straight to picking a .py file, or a folder - if you pick a folder, it runs batch.py inside it (the fixed name Video Studio's export uses). Choose a target machine from the known peers, then click Run. The dialog switches to a status view listing script jobs with their state (running, finished, failed) and buttons to View, Cancel a running job, or Dismiss a finished one, plus a live console pane streaming that job's output. Only jobs started from this machine are tracked and listed here - a script sent to run on a remote peer runs there untracked by this dialog.

The same peer-dispatch mechanism also powers the "Distribute this job" checkbox in the AI Studios' Batch Preprocess and Batch Train dialogs - see the AI Studios manual - which sends a generated batch script to a remote peer instead of exiting INFINIWORKFLOW to run it locally.

Experimental Features

Robot Operating System (ROS)

ROS is a set of libraries used to communicate with robotic devices including robotic cars and arms.

Everything in a ROS system is a node, communicating with one another through topics, services, and actions.

Every ROS node in INFINIWORKFLOW corresponds to a ROS node in a ROS system.

Technically, INFINIWORKFLOW only supports ROS2, but they are referred to interchangeably in this manual.


ROS Publishers and Subscribers communicate by streaming data to and from a ROS topic.

ROS Publisher

The ROS2 Publisher node takes in a ROS topic name and a string message.

On trigger, it broadcasts the string message to the specified ROS topic once a second.

ROS Subscriber

The ROS2 Subscriber node takes in a ROS topic name as input.

On trigger, it outputs received messages from the specified ROS topic.


Devices that support ROS manifest themselves as ROS servers, which typically contain both service servers and action servers.

Instead of getting continual updates like publishers and subscribers, services only provide data or take effect when requested to by a client.

Like services, actions are only executed when called by a client. Unlike services, actions typically involve sending a goal and the action server can provide feedback on its progress towards that goal.

ROS Server

The ROS2 Server node takes in a ROS package name and executable file.

On trigger, this launches a ROS server that includes service and action servers.

By default, the ROS2 Server node launches the turtlesim_node of the turtlesim package, but this can be robotic arms, cars, or any other ROS node.

ROS Service Client

The ROS2 Service Client node takes in a ROS service name, the input type of the service, and args representing the input.

On trigger, this queries the specified ROS service with the args input for some information or effect.

By default, the node calls the /spawn service of the turtlesim_node, which spawns a turtle at its default position in the bottom left corner.

ROS Action Client

The ROS2 Action Client node takes in a ROS action name, the input type of the action, args representing the input, and a feedback bool.

On trigger, this uses the args input to set an objective for the specified ROS action and outputs its progression to that goal if feedback is true.

By default, the node calls the /turtle1/rotate_absolute action of the turtlesim_node, which rotates turtle1 to a specified angle; in this case, {theta: 1.57}.

The service can be any supported service on any ROS node, so the ROS2 Service and Action Client nodes can interact with devices like robotic arms and cars.

MCP Server using AnythingLLM

To have a prompt console where you can actually "ask" the AI to build or update your workflow, you need a Client that connects to the SSE (Server-Sent Events) port we just opened in your app (Port 8000). AnythingLLM is the easiest desktop console for MCP.

See the MCP / AI Agent page for live server status, how to start the server, copy-button setup snippets for Claude Code / Claude Desktop / AnythingLLM, the full tools reference, and a large set of example prompts. The app's Windows menu also has a quick "MCP AI Agent" launcher that opens a terminal running your agent CLI directly.

Security note: the server listens on all network interfaces with no authentication, so anything on your network that can reach port 8000 can read and modify your workflow while it's running. Only use -mcp on a trusted machine/network.

Generative AI

Chat with an AI coding agent wired to InfiniWorkflow's own MCP server, so it can edit the live workflow graph, generate and compile C++ plugins, drive AI Studio, inspect state, and control playback, all from natural-language requests. Both Claude (Anthropic, via the claude/Claude Code CLI) and ChatGPT (OpenAI, via the codex CLI) are supported. For the full walkthrough (prerequisites, opening the chatbox, conversation history, and what happens when you send a message) see the dedicated Generative AI guide.

Installation

System Requirements

INFINIWORKFLOW runs on a modern PC with Windows 11 or higher, or macOS 12.6.2 or higher. It requires an Intel or AMD processor, at least 12GB of free disk space, and ideally an NVIDIA GPU with sufficient VRAM for your models. A multicore processor is highly recommended, since execution runs noticeably smoother with one.

On Windows, the software also runs on machines without an NVIDIA GPU, but that significantly reduces performance, especially for ML workflows. A package with no dependencies on CUDA or PyTorch is also available to download - it doesn't require an NVIDIA GPU to be present on your system and is substantially smaller in size, but it doesn't let you build deep learning models and is slower for AI inference.

You must also have a recent Google Chrome browser installed - version 131.0.6778.140 or higher.

Downloadable Packages

The following are the full set of downloads packages:

Application Packages

Operating System CUDA Installation Non-CUDA Installation
Windows infiniworkflow infiniworkflow_noncuda
MacOSX x86_64 Not applicable infiniworkflow_osx_x86_64
MacOSX arm64 Not applicable infiniworkflow_osx_arm64
Linux x86_64 (Ubuntu24.04 LTS) infiniworkflow_linux Not available
Nvidia Jetson infiniworkflow_jetson Not available
AWS Cloud Contact Photron Not available

Patch Update Packages

Patch install of latest binary build with reduced size (does not include Python or bin folder)
Operating System Link
INFINIWORKFLOW PATCH - Windows infiniworkflow_patch
INFINIWORKFLOW PATCH - MacOSX x86_64 infiniworkflow_osx_patch
INFINIWORKFLOW PATCH - MacOSX arm64 infiniworkflow_osx_patch
INFINIWORKFLOW PATCH - Linux infiniworkflow_linux_patch
INFINIWORKFLOW PATCH - Jetson infiniworkflow_jetson_patch

Installation Steps

Windows

  1. Double-click install.bat in the unzipped folder and grant Administrative privileges.
    Note: Admin rights are only used to configure Windows Firewall for the local webserver.
  2. Allow approximately 30 minutes for the installation of Python modules. Ensure you have an active network connection.
  3. Once complete, launch INFINIWORKFLOW using the Desktop Shortcut or by running INFINIWORKFLOW.bat.
⚠️ System Requirement: Please ensure your NVIDIA graphics driver is updated to at least version 576.88.

macOS

First, verify your system architecture:

python3 -c "import platform; print(platform.processor())"
  1. Ensure you have Python v3.13 installed.
  2. In the unzipped folder, run sudo sh install.sh and enter your password.
  3. Allow 5 minutes for module installation.
  4. Run sh INFINIWORKFLOW.sh to start.

Linux

  1. Run sudo sh install.sh in the unzipped folder and provide your password.
  2. Allow 30 minutes for Python module installation.
  3. Run sh INFINIWORKFLOW.sh to start.

Jetson

  1. Run ./install.sh in the unzipped folder and provide your password.
  2. Allow 30 minutes for module installation.
  3. Run ./INFINIWORKFLOW.sh to start.

Post Installation

A webpage displayed in the Google Chrome browser should appear - if another browser shows up then change your default browser to Chrome and redo this step. The first thing that will be displayed in the browser is the INFINIWORKFLOW EULA which you must agree to. You will also see a Windows dialog that requests "Do you want to allow public and private networks to access the app?" for Python - you must allow access.

Firewall Access (Windows only)

When you install INFINIWORKFLOW and run it the first time, you may see a Windows dialog that requests "Do you want to allow public and private networks to access the app?" for Python - you must allow access. If this dialog does not pop up and INFINWORKFLOW does not show images in the viewer then you have to manually grant access to allow INFINIWORKFLOW's Python installation to have access to public and private networks as follows:

After you have completed this you will see the following:

If your Firewall is controlled by your anti-virus software then you will need to allow access of INFINIWORKFLOW's python.exe using the anti-virus software.

Running as an Auto-Restart Service

For an unattended Network Manager peer or any other headless render server, you generally want INFINIWORKFLOW to come back on its own after a crash, an uncaught exception, or someone closing the console window - not sit down until an admin notices. scripts/iw_watchdog.py is a small, cross-platform supervisor for exactly that: it starts INFINIWORKFLOW, waits for it to exit, and restarts it, with a crash-loop guard (a rolling restart-rate limit plus a minimum-uptime check) so a broken config can't tight-loop the machine instead of just backing off and trying again. It never gives up permanently - "keep restarting it" is the whole point.

The watchdog does not itself register as a systemd unit, a launchd job, or a Windows service - it is a plain long-running script. Each platform's own service manager is used only to keep the watchdog alive at boot (it rarely crashes; it is a small restart loop), while the watchdog is what actually supervises INFINIWORKFLOW and restarts it, with the same behavior on every OS instead of three different native "restart on failure" mechanisms.

Run it manually to check it works before installing it as a service:

python iw_watchdog.py --dir "C:\InfiniWorkflow" --extra-args "-nobrowser -port 5000"

--dir is the INFINIWORKFLOW install root (the folder containing app/, and on Windows the bundled python.exe) - it defaults to the current directory, so pass it explicitly for a service that won't start with a known working directory. --extra-args forwards its value to app.py as a single shell-quoted string (-nobrowser is added automatically if not already present). Restart-loop tuning defaults to 5 restarts per 300-second window before a 60-second backoff, and any exit faster than 10 seconds is always treated as a crash-loop tick regardless of the rolling window; all of these, plus --python (override the interpreter) and --log (defaults to <dir>/logs/iw_watchdog.log, shared by both the watchdog's own restart events and INFINIWORKFLOW's stdout/stderr), are documented in python iw_watchdog.py --help.

For the Network Manager peer case specifically, --extra-args is where the -distributed-listen/-distributed-token flags actually go, alongside whatever other startup flags you'd normally pass to app.py:

python iw_watchdog.py --dir "C:\InfiniWorkflow" --extra-args "-nobrowser -distributed-listen -distributed-token my-shared-secret"

See Command line arguments for the full reference - -distributed-listen opts this instance in to accepting jobs on the control channel (port 5099), and -distributed-token is the shared secret both the orchestrator and this listening instance must agree on; without it, this instance refuses all incoming jobs regardless of -distributed-listen. Any other flag documented there (-resolution, -port, etc.) can be added to the same --extra-args string.

On a clean stop (Ctrl+C, or a service manager's own stop signal) the watchdog exits without restarting. On POSIX, that stop signal is forwarded to INFINIWORKFLOW as SIGTERM - exactly what app.py's own signal handler is registered for, so a clean stop also runs the same distributed-renderer cleanup a normal exit does. On Windows, TerminateProcess cannot deliver a clean signal to another process, so a stop there is abrupt by necessity; INFINIWORKFLOW's own startup sweep (sweep_stale_local_renderers()) cleans up anything that abrupt stop left behind the next time it starts.

systemd (Linux)

Create /etc/systemd/system/infiniworkflow-watchdog.service:

[Unit]
Description=INFINIWORKFLOW auto-restart watchdog
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/python3 /opt/infiniworkflow/scripts/iw_watchdog.py --dir /opt/infiniworkflow
Restart=on-failure
RestartSec=5
User=infiniworkflow

[Install]
WantedBy=multi-user.target

Then enable and start it:

sudo systemctl daemon-reload
sudo systemctl enable --now infiniworkflow-watchdog

launchd (macOS)

Create ~/Library/LaunchAgents/com.photron.infiniworkflow-watchdog.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.photron.infiniworkflow-watchdog</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/python3</string>
        <string>/opt/infiniworkflow/scripts/iw_watchdog.py</string>
        <string>--dir</string>
        <string>/opt/infiniworkflow</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
</dict>
</plist>

Then load it:

launchctl load ~/Library/LaunchAgents/com.photron.infiniworkflow-watchdog.plist

Windows (NSSM)

Windows has no built-in way to run a plain script as a service, so use NSSM (the Non-Sucking Service Manager) as a thin wrapper:

nssm install InfiniWorkflowWatchdog "C:\InfiniWorkflow\python.exe" "C:\InfiniWorkflow\scripts\iw_watchdog.py --dir C:\InfiniWorkflow"
nssm set InfiniWorkflowWatchdog AppDirectory "C:\InfiniWorkflow"
nssm set InfiniWorkflowWatchdog Start SERVICE_AUTO_START
nssm start InfiniWorkflowWatchdog

A Scheduled Task ("Run whether user is logged on or not", triggered "At startup") is a lighter-weight alternative to NSSM if you'd rather not install a third-party tool - it won't restart the watchdog itself if it dies, but the watchdog process itself is small and stable enough that this is rarely a practical concern.

Feature Packages

Name OS Description Link
INFINIWORKFLOW SDK SDK to allow you to write your own Python and C++ Plugins for INFINIWORKFLOW infiniworkflow_sdk
Code Generation Python Codegen package for Python GUI codegenpy
OpenCV Barcode Detection Inference WeChat QRCode including CNN models for `wechat_qrcode` module, including the detector model and the super scale model barcode
Labeling and Finetuning Finetuning and Label labeling_finetuning
Medical Blood Cell Detection medical
Aviation Plane Detection aviation
Road Infrastructure Road Crack Detection and Segmentation road_infrastructure
Warehouse Warehouse Detection warehouse
Satellite Satellite Imagery Building Detection satellite
Emergency Fire and Smoke Detection for Emergency Response emergency
Cityscapes Segmentation Training and Testing Semantic Understanding of Urban Street Scenes cityscapes
Colorization Inference Colorful Image Colorization colorization
Tracking Inference, DaSiamRPN Formulates the task of visual tracking as a task of localization and identification simultaneously using DaSiamRPN algorithm dasiamrpn
Tracking Inference, Nano Formulates the task of visual tracking as a task of localization and identification simultaneously using Nano Tracker algorithm nano
Holistic Edge Inference Code for holistic edge detection using pretrained hed model(caffe) edge
DexiNed Edge Inference Code for edge detection using a model(ONNX) using a Convolutional Neural Network (CNN) dexined
Nano Font Noto Sans JP — Japanese font from the Noto font family nano_font
Face Detect Inference using Haarcascades Face Detect Inference using Haarcascades using OpenCV haarcascades
Human Face Segmentation Human Face Segmentation human
Mask Segmentation Inference Mask Segmentation mask_rccn
Person Reidentification Inference Person REID Inference personReiD
MiDaS Depth Inference MiDaS computes relative inverse depth from a single image midas
Hand and Body Pose Inference OpenCV Hand and Body Pose Inference pose
Segmentation Inference A Deep Neural Network Architecture for Real-Time Semantic Segmentation segmentation
Human Segmentation Inference A Deep Neural Network Architecture for Real-Time Segmentation on Humans Specifically human_seg_pp
OpenCV Text Spotting Detection Inference An End-to-End Trainable Neural Network for Image-based Sequence Recognition and Its Application to Scene Text Recognition text_spotting
Text Detection PP-OCRv3 Inference Text Detection using PP-OCRv3 Model. text_detect_ppocr
YuNET Face Tracking and Facial Expressions Recognition Inference A Light-weight, Fast, and Accurate face Detection Model, with Ability to Track Faces and Points on a Face and Perform Facial Expression Recognition yunet
UTKFace Dataset UTKFace dataset is a large-scale face dataset with long age span utkface
YOLO4 Darknet Object Detection Inference A computer vision model that uses YOLO4 deep learning using Darknet to detect objects in images and videos yolodarknet4
YOLO4 Tiny Darknet Object Detection Inference A computer vision model that uses YOLO4 Tiny deep learning using Darknet to detect objects in images and videos yolodarknet4tiny
YOLO7 Darknet Object Detection Inference A computer vision model that uses YOLO7 deep learning using Darknet to detect objects in images and videos yolodarknet7
YOLO7 Tiny Darknet Object Detection Inference A computer vision model that uses YOLO7 Tiny deep learning using Darknet to detect objects in images and videos yolodarknet7tiny
YOLO NAS Object Detection Inference A computer vision model that uses YOLO7 deep learning to detect objects in images and videos yolonas
Custom YOLO3 using Darknet A computer vision model using YOLO3 using Darknet that allows you to customize and train as well as do inference on the trained models

Photron does not distribute YOLO3 as part of INFINIWORKFLOW, if you wish to use YOLO3, you must download it separately and agree to the license terms on your usage:

After installing

1. Create a new directory in the assets folder:

INFINIWORKFLOW_PATH/assets/yolov3

1. Download https://github.com/patrick013/Object-Detection---Yolov3/blob/master/model/yolov3.weights

2. Unzip file and copy yolov3.weights to:

INFINIWORKFLOW_PATH/assets/yolov3/yolov3.weights

3. Download https://github.com/pjreddie/darknet/blob/master/cfg/yolov3.cfg

4. Copy yolov3.cfg to:

INFINIWORKFLOW_PATH/assets/yolov3/yolov3.cfg

custom_yolo3
YOLO5 Ultralytics Object Detection Inference A computer vision model that uses YOLO5 deep learning to detect objects in images and videos

Photron does not distribute YOLO5 as part of INFINIWORKFLOW, if you wish to use YOLO5, you must download it separately and agree to the license terms on your usage: LICENSE

Additional steps:

After installing the patch

1. Create a new directory in the assets folder:

INFINIWORKFLOW_PATH/assets/yolo5

1. Download https://github.com/RsGoksel/Cpp-Object-Detection-Yolov5-OpenCV/releases/download/ONNX/yolov5s.onnx

2. Copy yolov5s.onnx to:

INFINIWORKFLOW_PATH/assets/yolo5/yolov5s.onnx

3. Download https://github.com/RsGoksel/Cpp-Object-Detection-Yolov5-OpenCV/blob/main/Yolov5_Image_Object_Detection/Models/classes.txt

4. Copy classes.txt to:

INFINIWORKFLOW_PATH/assets/yolo5/classes.txt

yolo
YOLO7 Ultralytics Object Detection Inference A computer vision model that uses YOLO7 deep learning to detect objects in images and videos

LICENSE

Additional steps:

After installing the patch

1. Create a new directory in the assets folder:

INFINIWORKFLOW_PATH/assets/yolo7

1. Download https://dl.opencv.org/models/yolov7/yolov7.onnx

2. Copy yolov7.onnx to:

INFINIWORKFLOW_PATH/assets/yolo7/yolov7.onnx
yolo7
YOLO8 Ultralytics Object Detection Inference A computer vision model that uses YOLO8 deep learning to detect objects in images and videos

LICENSE

Additional steps:

After installing the patch

1. Create a new directory in the assets folder:

INFINIWORKFLOW_PATH/assets/yolo8

1. Download https://dl.opencv.org/models/yolov8/yolov8n.onnx

2. Copy yolov8n.onnx to:

INFINIWORKFLOW_PATH/assets/yolo8/yolov8n.onnx
yolo8
YOLO9 Ultralytics Object Detection Inference A computer vision model that uses YOLO9 deep learning to detect objects in images and videos

LICENSE

Additional steps:

After installing the patch

1. Create a new directory in the assets folder:

INFINIWORKFLOW_PATH/assets/yolo9

1. Download https://dl.opencv.org/models/yolov9/yolov9t.onnx

2. Copy yolov9t.onnx to:

INFINIWORKFLOW_PATH/assets/yolo9/yolov9t.onnx
yolo9
YOLO10 Ultralytics Object Detection Inference A computer vision model that uses YOLO10 deep learning to detect objects in images and videos

LICENSE

Additional steps:

After installing the patch

1. Create a new directory in the assets folder:

INFINIWORKFLOW_PATH/assets/yolo10

1. Download https://dl.opencv.org/models/yolov10/yolov10s.onnx

2. Copy yolov10s.onnx to:

INFINIWORKFLOW_PATH/assets/yolo10/yolov10s.onnx
yolo10
YOLOX Inference YOLOX is a high-performing object detector based on the YOLO series yolox_inference
Yahoo Finance API Realtime Yahoo Finance quotes yfinance
Philips Hue Trigger Philips Hue Lights philips_hue
Geo API Geo and Geo Reverse geopy
Slack Send Slack Message slack_utility
Send Email Send Email send_email
Blink1 Blink1 LED Light blink
Upload Video Upload Video upload_video
Google Drive Google Drive Upload and Download google_drive
AWS S3 AWS S3 Upload and Download aws_s3
Azure Azure Upload and Download azure
Live Stream Live Stream live_stream
PyRender PyRender - 3D Rendering pyrender
YouTube Reader YouTube Reader youtube_reader
Livestream Chat Livestream Chat livestream_chat
OpenNI Depth Sensor OpenNI Depth Sensor openni_depth_sensor_windows
Mask 2 Former A unified framework for panoptic, instance and semantic segmentation mask2former
ONNX Runtime Accelrated C++ Inference engine for running ONNX models onnx_runtime_windows
YOLOX Train YOLOX Train yolox_train
Audio Audio
Additional steps:

After installing the patch

1. Download FFMPEG:

https://ffmpeg.org/download.html

2. Place the ffmpeg executable in your path, or in external/bin folder
audio
Audio Classify Audio Classify audio_classify
Database Database database
Robot Operating System (ROS) A set of libraries that communicates data and actions across sensors and robotic devices.

Photron does not distribute ROS as part of INFINIWORKFLOW, if you wish to use ROS, you must download it separately and agree to the license terms on your usage: ROS2 LICENSE

Additional steps:

1. Install ROS2: https://docs.ros.org/en/jazzy/Installation/Ubuntu-Install-Debs.html

2. Make sure you source the ROS environment:

source /opt/ros/jazzy/setup.bash

3. Start INFINIWORKFLOW using

LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../external/bin/onnxruntime/:../external/bin/opencv2/:../external/bin/ python3 app.py

ros2
RTCBot RTCBot rtcbot
Serial Serial serial
OCR OCR ocr
Text to Speech Speech Synthesis text2speech
MQTT MQTT Publish and Subscribe for factory-floor/IoT messaging mqtt
Modbus Modbus TCP Read and Write for PLCs and factory equipment modbus
QR Code and Barcode Generator Generate QR Code and Barcode images from text qr_barcode_generator

Installation Patches

There are three flavours of patches - one is a patch to the application, one is a SDK patch and the others are feature patches to allow installation of different demos and packages. See the Downloadable Packages for the full list. The application patch is meant to patch your exisiting installation with a smaller set of files and thus has a substantially smaller download size. It is expected that the application patch will be frequently updated when bugs are fixed and small features added. To patch your exisiting installation you should download the patch, and then open a Windows Powershell prompt and then change the directory to your existing INFINIWORKFLOW installation (i.e. where you unzipped your original installation). Then type the following where you should replace /folder/to/ to the actual folder you downloaded the application patch:

Installation Packages

The packages (feature patches) are meant to allow new functionaility including demos and assets such as the ML model. For example you can download the YOLO classifier feature patch, yolo_v1_0.zip then install by open a Windows Powershell prompt and then change the directory to your existing INFINIWORKFLOW installation (i.e. where you unzipped your original installation) and type the following where you should replace /folder/to/ to the actual folder you downloaded the feature patch:

User Authentication

To ensure security, INFINIWORKFLOW provides the ability to check User Authentication before users may access the application. This is not enabled by default, but can be enabled easily by your administrator by running the following python script to create a INFINIWORKFLOW superuser:

        cd /path/to/INFINIWORKFLOW/app
        python3 create_superuser_script.py
    

With a superuser created, User Authentication is enabled. Now, when starting INFINIWORKFLOW, users will reach the login page (as seen below) and have to enter their login information to continue to INFINIWORKFLOW.

When a user is finished using Infiniworkflow, they may click "Yes" or "Save and Exit" to exit the application, or they may click "Logout", which saves the current workflow and logs out of the session, returning back to the login screen.

As an Admin, you will have extended permissions that regular users won't, which includes making and removing users and groups. To access these controls, click on the Admin link and enter your admin username and password to continue. You will then reach a page like this, with all of the Admin controls available.

Command line arguments

You can start INFINIWORKFLOW from the command line. To successfully execute you need to change the current directory to the app folder located under INFINIWORKFLOW and then run the command:

Note, on OSX and Linux instead of using "..\python.exe", you should use "python3"

..\python.exe app.pyc
    [-help]
    [-url ...]
    [-port ...]
    [-device #]
    [-cuda ...]
    [-batch]
    [-final node name or node uuid]
    [-override json]
    [-nobrowser]
    [-path ...]
    [-source ...]
    [-resolution ...]
    [-test ...]
    [-fps ...]
    [-mcp]
    [-label_variations directory]
    [-movie movie_prefix]
    [-clean]
    [-studio]
    [-distributed-listen]
    [-distributed-token ...]
    [-clip_uuid ...]
    [-clip_start ...]
    [-clip_end ...]
    [-clip_result ...]
    [workflow]
Argument name Description Default Value Example
-url url the server will start on, if not specified starts on localhost 127.0.0.1
python app.py -url 192.168.5.52
-device allows you to set the default GPU device used 0
..\python.exe app.pyc -device 1
-cuda enable or disable cuda
system will test system again to determine if cuda is available
auto will use prior system check
options: [auto|on|off|system]
auto
..\python.exe app.pyc -cuda off
-batch batch mode will not show UI
..\python.exe app.pyc -batch
-final if in batch mode you can set the final node that you wish to execute before you exit. Either pass in node name or node uuid
..\python.exe app.pyc -final R2Score
-override a json string that allows you to override attributes in the workflow you pass
..\python.exe app.pyc -final "{'Set Int.value' : '5', 'Set Int1.value' : '11' }"
-help shows a help message
..\python.exe app.pyc -help"
-port specify which network port to use, if none specified then 5000 is used 5000
..\python.exe app.pyc -port 8888"
-nobrowser does not automatically open a browser
..\python.exe app.pyc -nobrowser"
-path establishes paths that can be used as a prefix
..\python.exe app.pyc -path "captures=C:\Users\imagi\CapturesFolder;media=C:\media"
-source creates a workflow with a movie reader with this media
..\python.exe app.pyc -path "media=C:\media_folder" -source media:movie.mp4
-test Sets the project resolution
..\python.exe app.pyc -resolution 1920x1080
-test See Automated Testing
..\python.exe app.pyc -test yolo
-label Allow labelling of workflows used for training LLM
..\python.exe app.pyc -label
-fps Set python rendering fps 60
..\python.exe app.pyc -fps 100
-mcp Starts MCP server. See MCP Server
..\python.exe app.pyc -mcp
-label_variations Runs batch variation preprocessing for the specified directory (e.g., assets folder).
..\python.exe app.py -batch -label_variations ..\assets\AI_Welding
-movie Filter variation subdirectories under the .variations folder when running -label_variations. If specified, only folders starting with the given name/prefix (e.g., "bighole" matching "bighole - Copy", "bighole - Variation #1") are searched, cleaned, and processed.
..\python.exe app.py -batch -label_variations ..\assets\AI_Welding -movie bighole
-devices (Used with run_batch_preprocess.py) Number of devices (e.g. GPUs) to distribute batches over. If set to 2, it creates 2x more batches, passing -device 0 to the first half and -device 1 to the second half. 1
..\python.exe run_batch_preprocess.py -label_variations ..\assets\AI_Welding -devices 2
-clean Force full recomputation of variations when used with -label_variations by deleting existing completion cookies and images first. Supports -movie filtering.
..\python.exe app.py -batch -clean -label_variations ..\assets\AI_Welding
-resolution Sets the initial viewer resolution, as WIDTHxHEIGHT
..\python.exe app.pyc -resolution 1920x1080
-studio Opens directly into Studio mode instead of the default editor view
..\python.exe app.pyc -studio
-distributed-listen Accept Network Manager jobs pushed from another INFINIWORKFLOW instance on the control channel (port 5099) and run them here - opt-in, requires -distributed-token to actually accept anything
..\python.exe app.pyc -distributed-listen -distributed-token my-shared-secret
-distributed-token Shared secret required on both ends of a Network Manager job dispatch (the orchestrator sending it and the -distributed-listen instance receiving it) - without it, a -distributed-listen instance refuses all incoming jobs and an orchestrator refuses to send to a remote target
..\python.exe app.pyc -distributed-token my-shared-secret
-clip_uuid (Batch mode, internal - Render to Clip remote dispatch) uuid of the cv.video_writer node to bound-export. Not intended to be set by hand - the orchestrating instance passes this automatically when dispatching a clip render to a remote peer.
-clip_start (Batch mode, internal) First frame of the -clip_uuid bounded export
-clip_end (Batch mode, internal) Last frame of the -clip_uuid bounded export
-clip_result (Batch mode, internal) Path to write the clip render result JSON to before exiting
workflow The final argument is the workflow json file
..\python.exe app.pyc  ..\demos\Untitled\Untitiled.json"

Known Issues

Plugin SDK

Plugins can be implemented in C++ or Python and both will require a JSON file. The JSON Schema specifies the input and output parameters as well as the name and description of the plugin amongst other things.

To start creating your own plugin, it is recommended you base your code on the Canny2 plugin that is provided upon installation. For Windows users, you can immeadiately run the Canny2 plugin via the Visual Studios solution. For Mac and Linux users, the process of creating a plugin will require a few more steps. These steps are detailed below in the section "Creating Plugins for Mac/Linux"

Customizing Your own Tools

A simple way to make your own tool without writing Python or C++ code is to simply use an existing tool and customize its parameters. You simply create an updated JSON for the tool and place it in the extensions folder. You can get the JSONs for the exisiting tools in the subfolders in the app/catalog folder. For example, say we want to customize the "Lift" Tool to create a new "Red Lift" Tool - this tool would allow the lift color correction but the default value for the red parameter would be higher. The steps are as follows:

JSON Schema

All plugins must have an accompanying JSON file. The JSON file specifies the input and output parameters as well as the name and description of the plugin amongst other things. The specification of the schema is as follows:

Attribute name Mandatory Default Value Description Example
title The UI name of the plugin
"title" : "Canny Edge Detector"
Or you can specify a localized set
"title": {
    "en_US": "Canny Edge Detector",
    "ja-JP": "キャニーエッジ検出器",
    "es-ES": "Detector de bordes Canny",
    "de_DE": "Canny Kantendetektor",
    "zh_CN": "Canny 边缘检测器"
}
identifier The name of the plugin file Python:
"identifier": "day_of_week.py"
C++:
"identifier": "Canny2.plugin"
description The description that explains the purpose of this plugin which will be shown in the UI
"description" : "Canny Edge Detection is a popular edge detection algorithm"
Or you can specify a localized set
"description": {
    "en_US": "Canny Edge Detection is a popular edge detection algorithm",
    "ja-JP": "Canny Edge Detectionは人気のエッジ検出アルゴリズムです",
    "es-ES": "Canny Edge Detection es un popular algoritmo de detección de bordes",
    "de_DE": "Canny Edge Detection ist ein beliebter Kantenerkennungsalgorithmus",
    "zh_CN": "Canny 边缘检测是一种流行的边缘检测算法"
}
url www.photron.com A URL that is shown in the UI to have more information about the plugin
"url": "https://docs.opencv.org/3.4/dd/d1a/group__imgproc__feature.html#ga04723e007ed888ddf11d9ba04e2232de"
tags A list of tags that is associated with the plugin
"tags": ["opencv", "edges", "canny"]
Or you can specify a localized set:
"tags": {
    "en_US": ["opencv", "edges", "canny"],
    "ja-JP": ["オープンCV", "エッジ", "賢い"],
    "es-ES": ["abrircv", "bordes", "astuto"],
    "de_DE": ["OpenCV", "Kanten", "schlau"],
    "zh_CN": ["opencv", "边缘", "精明的" ]
}
icon
"icon": "bi-heart-fill"
A bootstrap icon that represents the plugin in the UI
"icon": "bi-star"
category The category the plugin will be placed in the Toolbox If you want to specify your own new category
"category": {
    "id": "python_scripts",
    "description": "User defined python scripts",
    "icon": "bi-filetype-py"
}
If you want to place it in an exisiting category
"category": {
    "id": "Photron"
}
language Must be either python, c++ or cuda
"language": "c++"
gpu
"gpu": false
Informs if CUDA GPU is recommended for execution
"gpu": true
os
"os": ["windows", "osx", "linux"]
Specifies if the plugin wants to limit which Operating Systems the plugin will be available
"os": ["osx"]
supervise
"supervise": false
Specifies if the plugin wants to handle supervion callbacks to enable/disable or hide/show parameters dynamically Note you must also set one of the input parameters to have a supervise attribute to be true which are the parameters that cause other parameters to change visibility
"supervise": true
supervise_values
"supervise_values": []
Specifies if the plugin wants to handle supervion callbacks to dynamically set values, specify the list of identifiers you want to update their values on a supervised change
"supervise_values": ["color", "opacity"]
inputs
"inputs": []
An array of input objects that specifies each input of the plugin - see inputs schema
"inputs": [
    {
        "name": "source",
        "type": "image2D",
        "mandatory": true,
        "description":"Input image",
        "identifier": "source"
    },
    {
        "name": "threshold1",
        "type": "double",
        "default": "100.0",
        "mandatory": true,
        "description": "First threshold for the hysteresis procedure",
        "identifier": "threshold1"
    },
...
]
                
outputs
"outputs": []
An array of output objects that specifies each output of the plugin - see outputs schema
"outputs": [
{
    "name": "out",
    "type": "image2D",
    "description": "Output edge map; single channels 8-bit image, which has the same size as image",
    "identifier": "out"
}
] 
overlay
"overlay": []
An array of svg elements that are drawn in the viewer when the node is viewed, the markup has a special inputs attribute to specify the list of input parameters
"overlay": [
    "<polygon stroke='yellow' opacity='0.5' stroke-width='2' fill='none' inputs='src[0],src[1],src[2]' />",
    "<polygon stroke='limegreen' opacity='0.5' stroke-width='2' fill='none' inputs='dst[0],dst[1],dst[2]' />"
  ]

Schema: inputs

Attribute name Mandatory Default Value Description Example
name The UI name of the input parameter
"name" : "out"
Or you can specify a localized set
"name": {
    "en_US": "out",
    "ja-JP": "出力",
    "es-ES": "afuera",
    "de_DE": "aus",
    "zh_CN": "出去"
identifier The unique identifier for this input parameter
"identifier": "out"
description The description that explains the purpose of this output
"description" : "Second threshold for the hysteresis procedure"
Or you can specify a localized set
"description": {
    "en_US": "Second threshold for the hysteresis procedure",
    "ja-JP": "ヒステリシス手順の2番目の閾値",
    "es-ES": "Segundo umbral para el procedimiento de histéresis",
    "de_DE": "Zweiter Grenzwert für das Hystereseverfahren",
    "zh_CN": "滞后过程的第二个阈值"
}
type The type of the parameter which which include the standard types: int, double, int2, double2, bool, string, numeric, image2D, cuda2D. Or you can define your own type name.
"type": "double"
mandatory
"mandatory": false
Specifies if the input parameter is mandatory and must be set by the user.
"mandatory": true
default The default value of the input parameter which is must be enclosed in a string. No default values should be needed for types that are not set directly by the user e.g. image2D and cuda2D
"default": "200.0"
min Only for numeric types such as int or double. The minimum value the input value can be set to
"min": 5.0
max Only for numeric types such as int/int2/int3 or double/double2/double3. The maximum value the input value can be set to
"max": 10.0
softmin
"softmin": false
Only for numeric types such as int/int2/int3 or double/double2/double3 that are not sliders but textfields. If softmin is true then the limit is only via the dragging of the UI, if you enter manually in the textfield the limit does not apply
"softmin": true
softmax
"softmax": false
Only for numeric types such as int/int2/int3 or double/double2/double3 that are not sliders but textfields. If softmax is true then the limit is only via the dragging of the UI, if you enter manually in the textfield the limit does not apply
"softmax": true
step Only for numeric types such as int or double. The step value the increments of the parameter UI will jump up and down
"step": 1.0
permitted Only for int or string types. An array of strings that will be in the selection UI menu or the tag selection UI
private
"private": false
Will not show the parameter in the UI
"private": true
editable
"editable": true
If the parameter can be editable or not, if not editable it will be disabled in the UI
"editable": false
hidden
"hidden": false
If the input is shown in the flowgraph
"hidden": true
editor_hidden
"editor_hidden": false
If the parameter is shown in the editor UI
"editor_hidden": true
multiple
"multiple": false
Only for string types that will allow multiple values to entered in the tag UI
"multiple": true
userOptionAllowed
"userOptionAllowed": false
Only for string types that allow user defined strings to be entered in the tag UI
"userOptionAllowed": true
look A hint to indicate how the UI should be represented instead of the default look
int types: button, slider
int2, double2, numeric2: point
string: map, filebrowser, curve, path, table, html, week, month, time, date, datetime-local
"look": "button"
icon
"icon": "bi-fire"
The icon for parameters that have a button look
"icon": "bi-robot"
maxrows
"maxrows": 100
Only for table looks to set the maximum number of rows for the table
"maxrows": 2
maxcols
"maxcols": 100
Only for table looks to set the maximum number of columns for the table
"maxcols": 2
random
"random": false
Only for color, int, int2, int3, double, double2, double3 types that ignores the default value and sets a random value instead
"random": true
ganged Only for int2, double2, numeric2 types that allows both the dimensions to be ganged and set to the same value
"ganged": "button"
multiline
"multiline": false
Only for string types that indicate if the UI should have a text or a single textfield widget
"multiline": true
rows Only for string types with a multiline set to true, indicates the number of rows of the text widget
"rows": 5
cols Only for string types with a multiline set to true, indicates the number of columns of the text widget
"cols": 10
password Only for string types to make the text now show when you enter text in the widget
"password": true
supervise
"supervise": false
Specifies when this parameter changes if you want to handle supervion callbacks to enable/disable or hide/show parameters dynamically. Note you must also set the supervise attribute of the main JSON object to true as well
"supervise": true
smooth
"smooth": true
Only for path types that indicate if the path can have bezier smooth control handles
"smooth": false
moveonly
"moveonly": false
Only for path types that indicate if the path can only have points moved (no insertion or deletion of any points)
"moveonly": true

Schema: outputs

Attribute name Mandatory Default Value Description Example
name The UI name of the output parameter
"name" : "threshold2"
Or you can specify a localized set
"name": "name": {
"en_US": "threshold2",
"ja-JP": "閾値2",
"es-ES": "umbral2",
"de_DE": "Schwelle2",
"zh_CN": "阈值2"
}
identifier The unique identifier for this output parameter
"identifier": "threshold2"
description The description that explains the purpose of this output
"description" : "Output edge map; single channels 8-bit image, which has the same size as image"
Or you can specify a localized set
"description": {
    "en_US": "Output edge map; single channels 8-bit image, which has the same size as image",
    "ja-JP": "出力エッジマップ。画像と同じサイズの単一チャネル8ビット画像。",
    "es-ES": "Mapa de borde de salida; imagen de 8 bits de canales individuales, que tiene el mismo tamaño que la imagen",
    "de_DE": "Ausgabekantenkarte; Einzelkanal-8-Bit-Bild, das die gleiche Größe wie das Bild hat",
    "zh_CN": "输出边缘图;单通道8位图像,与图像大小相同"
}
type The type of the parameter which which include the standard types: int, double, int2, double2, bool, string, map, numeric, image2D, cuda2D. Or you can define your own type name.
"type": "image2D"
column_names For matrix2D, the list of column names used in the viewer when showing this output
"column_names": ["x", "y"]
graph
"graph": false
For matrix2D types, visualize by default as graph chart
"graph": true
look For string types, show as a DataFrame
"look": "DataFrame"
hidden
"hidden": false
If the output is shown in the flowgraph
"hidden": true

Python SDK

The Python SDK uses the PythonNode base class and at a minimum you need to define a new instance which you should return in the result variable. The final plugin will be the python script and should be placed in the Extensions folder together with its JSON file. A simple example is the days_of_weeks.py sample plugin provided. The python code is as follows

from python_node import PythonNode
import datetime
class DayOfWeekNode(PythonNode):
	def __init__(self):
		super().__init__()
		self.value = None

	def execute(self, host):
		if not host.is_enabled():
			self.value =  False
		else:
			year = host.get_input_int_value(0)
			month = host.get_input_int_value(1)
			day = host.get_input_int_value(2)

			self.value = datetime.datetime.strptime(str(day) + "/" + str(month+1) + "/" + str(year), "%d/%m/%Y").strftime('%A')

		host.set_output_value(0, self.value)
	
	....
		
	def copy(self, host):
		return DayOfWeekNode()

result = DayOfWeekNode()

If you wish to instead use an existing Node but with a different JSON, e.g. you want to use the GenericDataset tool but set the parameters and hide them, then no code is needed any instead the result variable should return the identifier of the existing tool:

result = "torch.generic_loader"

However, using the Python API provides you full capability as long as you override the PluginApi class which requires 3 at least methods to be implemented: copy, execute and view_html. The following methods should be overriden by your derived class of PluginApi

Instance method Mandatory Arguments Return type Purpose
copy
self, host : PluginHost
instance of this plugin class
This method will be called when INFINWORKFLOW requests a copy of an instance of this class which should return a deep copy.
execute
self, host : PluginHost
None
The method called when the plugin is executed usually when some input parameters have changed. You can call the host to get input values, e.g. host.get_input_int_value(...), and finally set the output value. If the execution was unsuccessful then you can call host.set_error_message with the error message If you want to have the node to be executed you can call host.set_dirty(True) otherwise the node will only get re-executed when input parameters have been modified
view_html
self, host : PluginHost, nth_output : int
string
The method is called after the execute method, when the output of node is viewed The view_html should return a html string that represents the output of the nth output. Typically, in the execute method you can compute output values and store them in instance variables of the class and then later in the view_html you can use those values to establish what HTML string you will pass back.
has_dynamic_inputs
self, host : PluginHost
bool
Returns if the plugin has dynamic inputs, defaults to False
has_dynamic_outputs
self, host : PluginHost
bool
Returns if the plugin has dynamic outputs, defaults to False
allows_inference_macro
self, host : PluginHost
bool
Returns if if the node allows inference macros to be created
update_inference_macro_json
self, host : PluginHost, tool_json : dict
None
Updated the Tool JSON for the inference macro
get_macro_identifier
self, host : PluginHost
str
Gets the base macro for the inference tool generation
reset_trigger_counters
self, host : PluginHost, nth_index : int
None
The trigger at the nth index should reset any internal state that you maintain
get_adornment
self, host : PluginHost, output_port_num : int, output_type : str
None
Returns the adornment in the UI, returning "1" adds the slicing adornment
supervise_inputs
self, host : PluginHost, inputs_flags : ctypes.c_int_array
False
Called to dynamically enable/disable or hide/show parameters. Modify inputs_flags using SUPERVISE_FLAG_HIDDEN (1) or SUPERVISE_FLAG_DISABLED (2).
supervise_value
self, host : PluginHost, nth_index : int
None
Called for indices listed in update_values in the JSON. Return a string (e.g., "0.0,0.0,1.0") to force a new value in the UI.

The methods for PluginApi have a instance of PluginHost, the host, which is a helper class that allows you to call INFINIWORKFLOW related functions. The execute method should for example call the methods to get input values (e.g. get_input_int_value) and set the output value (i.e. set_output_value). The following methods should can be called on the PluginHost

Instance method Purpose Example
get_input_value During exeuction you can get the value of an input to the plugin, where you pass the order of the parameter E.g. pass 0 for the first input parameter
value = host.get_input_value(3)
get_input_bool_value A helper method that calls get_input_value and returns the value as a bool Python type
value = host.get_input_bool_value(3)
get_input_int_value A helper method that calls get_input_value and returns the value as a int Pythontype
value = host.get_input_int_value(3)
get_input_numeric_value A helper method that calls get_input_value and returns a float, int or bool Python type
value = host.get_input_numeric_value(3)
get_input_string_value A helper method that calls get_input_value and returns a str Python type
value = host.get_input_string_value(3)
get_input_filename_value A helper method that calls get_input_value and returns a str Python type and resolves the path (replacing the ${assets} with the correct path)
value = host.get_input_filename_value(3)
get_input_map_value A helper method that calls get_input_value and returns a dict Python type
value = host.get_input_map_value(3)
get_input_bool_list_value A helper method that calls get_input_value and returns a list of bool Python type
value = host.get_input_bool_list_value(3)
get_input_numeric_list_value A helper method that calls get_input_value and returns a list of float, int or bool Python type
value = host.get_input_numeric_list_value(3)
get_input_string_list_value A helper method that calls get_input_value and returns a list of str Python type
value = host.get_input_string_list_value(3)
set_output_value During exeuction you can set the value of an output to the plugin, where you pass the order of the parameter and the value E.g. pass 0 for the first input parameter This also will set the dirty flag to False (see set_dirty)
host.set_output_value(0, result)
set_dirty During exeuction you can set if the node has been executed by setting dirty flag to False. This is automatically set when you set the outputs but you can set it to True if you want to have the node get executed again
host.set_dirty(True)
get_num_inputs Returns the number of inputs that plugin has
value = host.get_num_inputs()
get_num_outputs Returns the number of outputs that plugin has
value = host.get_num_outputs()
set_error_message Sets an error message that will be shown in the UI
host.error_message("Something bad happened")
is_enabled Returns if the node is enabled
value = host.is_enabled()
is_cancel_render Returns true if the user has pressed cancel during the execution, in which case you should return from execution
value = host.is_cancel_render()
convert_filepath_to_relative_path Returns the argument path from an absolute path to relative path i.e. will prefix the path with ${assets} as appropriate
updated_path = host.convert_filepath_to_relative_path(path)
get_source_time Returns the source time depending on where the source originated from upstream e.g. if the source is from a Movie it will be frame number or if it is a web camera then it will be the epoch time
source_time = host.get_source_time(path)
set_source_time Sets the source time, all further downstream nodes will inherit this time
host.get_source_time(source_time)
is_triggered Returns if the trigger parameter at the nth input has been triggered or not
host.is_triggered(counter, nth_index)
get_view_slice Returns the view slice value in viewer
host.get_view_slice()

C++ SDK

The C++ SDK is based on compiling a DLL using some standard headers and libraries provided in the INFINIWORFLOW SDK patch package. You can use the exisiting Canny2 example as a starting point and rename all the files to your plugin name. The final plugin will be a DLL but prefixed with the .plugin extension and should be placed in the Extensions folder together with its JSON file. The SDK is based on Microsoft Visual Studio 2022 and only supports x86_64 builds.

The following methods should be overriden by your derived class of PluginApi

Instance method signature Purpose
setup
bool setup(PluginHost * host);
Setup a Plugin and will be called anytime the thread to run the plugin is started
update
bool update(PluginHost * host, BlobHandle blob, int inputIndex);
Update the Plugin instance based on a change of the input blob This will be called anytime the user changes a property, the inputIndex is the index into the "inputs" array in the JSON representing the parameters Typically you can copy the value of the contents of the Blob instance (using the host API such as getAsDouble) and then copy this into your plugin instance
superviseInputs
bool superviseInputs(PluginHost * host, int* inputsFlags);
Called if the plugin sets "supervise" in the JSON and will allow you to enable/disable and/or hide or show parameters The inputsFlags is an array that is the size of the number of inputs and you are responsible to set the values You can set the flags SUPERVISE_FLAG_NORMAL (0) to have it shown regularly Or set it to the flag SUPERVISE_FLAG_HIDDEN (1) to have it hidden Or set it to the flag SUPERVISE_FLAG_DISABLED (2) to have it disabled
superviseValue
bool superviseValue(PluginHost* host, int index, char* value);
Called for indices listed in the "update_values" array in the node JSON. The value parameter is a 512-byte buffer. Return true and write a string to the buffer (e.g., a hex color or status text) to force a new value into the UI widget.
execute
bool execute(PluginHost * host);
Execute a Plugin - you can call the pluginGetOutputBlob to get the output blob Return true if success or false otherwise
isCached
bool isCached(PluginHost * host);
Asks node if it has cached any blob values inits instance variables If so then the host may call flushCache
flushCache
bool flushCache(PluginHost * host);
Asks node to flush its cache - anything it has stored must be released For example, if you have cached the image as a Mat then release it
teardown
bool teardown(PluginHost * host);
Teardown called anytime the thread to run the plugin is stopped
destroy
bool destroy(PluginHost * host);
Destroy a Plugin which is you can destroy your plugin instance data

The following methods should can be called on the PluginHost that is passed into the API methods of PluginApi

Signiture Purpose
BlobHandle getOutputBlob(int outputNum) Get the Output Blob handle which can be callied during the executePlugin call, the outputNum is the index into the "outputs" array in the JSON representing the output
void setNumOutputs(int numOutputs) Sets the number of outputs the blob supports and can be called during makePlugin
void setErrorMessage(const char *message) Notifies an error has occurred which will be shown in the UI
void isEnabled() Checks if the node is enabled, if not then the plugin should usually just copy source to output
bool hasOutputObservers(int outputIndex) Returns if the output is currently connected - only render the output if it has observers
cv::Mat& getAsImage2D(BlobHandle blob) From the blob handle get the reference to a two dimensional image represented by OpenCV matrix
cv::Mat& getAsMatrix2D(BlobHandle blob) From the blob handle get the reference to a two dimensional matrix represented by OpenCV matrix
double &getAsDouble(BlobHandle blob) From the blob handle get the double value it represents
int &getAsInt(BlobHandle blob) From the blob handle get the int value it represents
bool &getAsBool(BlobHandle blob) From the blob handle get the bool value it represents
std::string &getAsString(BlobHandle blob) From the blob handle get the string value it represents
std::string &getAsFilename(BlobHandle blob) From the blob handle get the filename value it represents, resolving the prefix ${assets}
double *getAsDouble2(BlobHandle blob) From the blob handle get the 2D double point value it represents
int *getAsInt2(BlobHandle blob) From the blob handle get the 2D integer point value it represents
float *getAsColor3f(BlobHandle blob) From the blob handle get the color RGB value it represents
void cloneFromImage(BlobHandle blob, cv::Mat& dest) From the blob handle gets a cloned copy (which may be opencv mat or cuda memory)
CudaSuite *getCudaSuite() Get Cuda Suite - may return nullptr if no cuda supported on host

The following methods should can be called on the CudaSuite

Signiture Purpose
bool allocateCudaImage(int width, int height, int type, int rowbytes, int numChannels, CudaImage& cudaImage) Allocate a Cuda Image on the device
void freeCudaImage(CudaImage& cudaImage) Free a Cuda Image
void setCudaImage(BlobHandle blob, const CudaImage& cudaImage) Set the Cuda Image to the output Blob
void cloneCudaImageFromBlob(BlobHandle blob, CudaImage& cudaImage) Copy and clone the cuda image from the input blob
void upload(const cv::Mat mat, CudaImage& cudaImage) Utility method to upload CPU image to Cuda device Image
cv::Mat download(CudaImage& cudaImage) Utility method to download to CPU image from Cuda device Image

Creating Plugins for Mac/Linux

As with the C++ SDK instructions, you can use the exisiting Canny2 example as a starting point and rename all the files to your plugin name. See the section above for instructions on how to do this.

With your JSON now set up, you will need to construct the CMakeLists.txt file for your plugin. Open Canny2's CMakeLists.txt for reference. In your plugin's CMakeLists.txt file, rename any instance of "canny2" to the name of your plugin. Everything else should be kept the same.

In your console, "cd" into the folder containing your plugin. For Canny2, this is in "infini-workflow/sdk/examples/Canny2". Once you are in this folder in your console, enter the following command to build x86_64 architecture:

cmake -B build . -G "Unix Makefiles"
For arm64 architecture enter the following command to build x86_64 architecture:
cmake -DCMAKE_VS_PLATFORM_NAME="arm64" -B build . -G "Unix Makefiles"
This will create a folder called "build" within the directory you are currently in. Then enter the following commands:
cd build
make
This should output a few lines of text, with the last one being "[100%] Built target {NAME_OF_PLUGIN}". Now when you run INFINIWORKFLOW on a Mac or Linux device, the plugin will be available and usable.

Shader SDK

The Shader SDK is based on OpenGL GLSL shader language. You can use the exisiting "ShaderExample" in the SDK as a starting point and rename all the files to your plugin. The final plugin will be a combination of a JSON file and a GLSL shader file and both should be placed in the Extensions folder. Additonally, the GLSL shader file should also be placed in the assets/shader folder as well. The shader names will match the names of the input parameters in the JSON file, an example GLSL file is as follows:

        #version 150 core

        in vec3 Color;
        in vec2 Texcoord;
        out vec4 outColor;
        uniform sampler2D source;

        uniform float brightness;
        uniform float redBrightness;
        uniform float greenBrightness;
        uniform float blueBrightness;

        void main()
        {
            vec4 pixel = texture(source, Texcoord);
            outColor = pixel * vec4(brightness + redBrightness, brightness + greenBrightness, brightness + blueBrightness, 1.0);
        }
    

The JSON file should have the name of the identifier the same name as the GLSL file. The first input as a string which defaults to the location of the shader file in the assets shaders directory. Next, the JSON file should have a inputs for each uniform, where the sampler2D input will be of type "texture2D". Finally, the JSON should have one output will be of type "texture2D" The example JSON is as follows for this GLSL file:

{
  "identifier": "example_shader.glsl",
  "description": {
    "en_US": "Example GPU GLSL Shader"
  },
  "url": "https://www.khronos.org/opengl/wiki/OpenGL_Shading_Language",
  "icon": "bi-plugin",
  "tags": [
      "opengl",
      "GLSL",
      "gain",
      "texture"
    ]
  },
  "language": "opengl",
  "inputs": [
    {
      "name": "shader",
      "type": "string",
      "private": true,
      "default": "${assets}/shaders/example_shader.glsl",
      "description": "Shader Source",
      "identifier": "shader"
    },
    {
      "name": "source",
      "type": "texture2D",
      "mandatory": true,
      "description": "Input texture",
      "identifier": "source"
    },
    {
      "name": "brightness",
      "type": "double",
      "default": "0.0",
      "min": "-1.0",
      "max": "4.0",
      "look": "slider",
      "mandatory": false,
      "description": "Overall brightness amount",
      "identifier": "brightness"
    },
    {
      "name": "redBrightness",
      "type": "double",
      "default": "1.0",
      "min": "0.0",
      "max": "4.0",
      "look": "slider",
      "mandatory": false,
      "description": "Red brightness amount",
      "identifier": "redBrightness"
    },
    {
      "name": "greenBrightness",
      "type": "double",
      "default": "1.0",
      "min": "0.0",
      "max": "4.0",
      "look": "slider",
      "mandatory": false,
      "description": "Green brightness amount",
      "identifier": "greenBrightness"
    },
    {
      "name": "blueBrightness",
      "type": "double",
      "default": "1.0",
      "min": "0.0",
      "max": "4.0",
      "look": "slider",
      "mandatory": false,
      "description": "Blue brightness amount",
      "identifier": "blueBrightness"
    }
  ],
  "outputs": [
    {
      "name": "out",
      "type": "texture2D",
      "description": "Output texture",
      "identifier": "out"
    }
  ],
  "title": {
    "en_US": "Example GLSL Shader"
  }
}
    

Automated Testing

To perform automated testing you will need to create a directory "tests" and in this directory place a json test script called "tasks.json". For example, if your test was called "assembly_line", then create a folder "tests/assembly_line" under INFINIWORKFLOW main installation folder. Then place any expected results in the folder "tests/assembly_line/expected_results" that will be used in the "assertEquals" task (see JSON testing schema below for details) To start testing, open a terminal/powershell and change the current directory to the app folder located under INFINIWORKFLOW and then run the command:

..\python.exe app.pyc -test assembly_line

Note, on OSX and Linux instead of using "..\python.exe", you should use "python3"

The terminal will show the results of the test. For example:

assert: YOLO5 Classification:numDetects expected 11 but got 10
assert: YOLO5 Classification:preview expected rmse 0.1 bit got 0.16262965760694073
exit_tests...
test summary: 0 out of 2 pass

Each assert you do in your test will result in saving a file to a subfolder "actual_results", for example, in the assembly_line example described above, the actual result files will be in the subfolder "tests/assembly_line/actual_results"

The format of the JSON schema will is as an array of tasks, for example:

{
  "tasks": [
    {
      "name": "showMessage",
      "message": {
        "en_US": "First, start with the Yolo demo"
      },
      "delay": 1000
    },
    {
      "name": "assertEquals",
      "node_name": "YOLO5 Classification",
      "output_port": "numDetects",
      "expected_value": 10
    },
    {
      "name": "assertEquals",
      "node_name": "YOLO5 Classification",
      "output_port": "preview",
      "expected_rmse": 0.1
    },
    {
      "name": "exitTests",
      "delay": 0
    }
  ],
  "workflow": "${demos}/Inference/Yolov5/yolov5.json",
  "on_error": "exit",
  "verbose": true
}

If you want to start the test by loading a workflow then include the "workflow" attribute that should be set to the workflow that will be loaded at the start of testing

If you want to exit testing if an assertion error occurs, then set the "on_error" attribute to "exit", otherwise set it to "continue" and it will continue further processing of the test even after an error has occurred.

Set the verbose attribute to true to see the results of the outputs of the testing in the terminal.

All testing should end with the task "exitTasks". The tasks allow you to do all the functionality you as the user can do with your mouse and keyboard - instead it is driven by your tasks in your script. The tasks are described as follows

Name Description Other Attributes Example
showMessage Shows a message in the bottom tooltip window
message string the message you display in the UI
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "showMessage",
                    "message": "First, start with the Yolo demo",
                    "delay": 1000
                }
                
hideMessage Hides a message in the bottom tooltip window
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "hideMessage",
                    "delay": 1000
                }
                
printOutput Prints the value of a node's output to the info dialog
node_name string name of node
output_port string name of output port
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "printOutput",
                    "node_name": "Yolo",
                    "output_port" : "out",
                    "delay": 1000
                }
                
assertEquals Asserts a node output value will be expected to be some value The actual result will be saved in the actual_results folder and compared against the file in the expected_results
node_name string name of node
output_port string the output port indentifier
expected_rmse double [optional] root mean sqaure error, only needed for image2D output comparisons
prefix string [optional] a prefix added to the saved actual result
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "assertEquals",
                    "node_name": "Classification",
                    "output_port" : "numDetects",
                    "delay": 1000
                }
                

In this case the file comparison will be "Classification_numDetects.png"

For matrix2D output types, the file is saved in csv format otherwise all other cases it is saved in a text (.txt) file"

If you specify the "prefix" attribute, then the file name is prefixed with this value

saveOutputImage Saves the output image for a node's output
node_name string name of node
output_port string the output port indentifier
path string path of file to be saved
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "saveOutputImage",
                    "node_name": "Yolo",
                    "output_port" : "preview",
                    "path" : "output.png",
                    "delay": 1000
                }
                
saveOutputMatrix Saves the output matrix for a node's output
node_name string name of node
output_port string the output port indentifier
path string path of file to be saved
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "saveOutputMatrix",
                    "node_name": "Yolo",
                    "output_port" : "out",
                    "path" : "output.png",
                    "delay": 1000
                }
                
exitTests Exits INFINIWORKFLOW and prints the test summary in the console
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "exitTests"
                }
                
addNode Adds a node from the Toolbox to the workflow
tool_id string the tool's unique indentifier
node_name string name of new node
mandatory_params list [optional] list of parameters that are mandatory e.g. filename for a movie reader
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "addNode",
                    "tool_id": "cv.movie_reader",
                    "mandatory_params": [
                        "$\{assets\}/city.mp4"
                    ],
                    "node_name": "Movie Reader",
                    "duration": 180,
                    "delay": 1000
                }
                
delay Wait a delay before proceeding to next task
delay int number of milliseconds delay to delay
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "delay",
                    "amount": 180,
                    "delay": 1000
                }
                
addLink Adds a link from the output of one node to the input of another node
from_name string the output node
from_port string the port indentifier of the output node
to_name string the input node
to_port string the port indentifier of the input node
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "addLink",
                    "from_name": "Movie Reader",
                    "from_port": "out",
                    "to_name": "Yolo Classifier",
                    "to_port": "source",
                    "duration": 300,
                    "delay": 1000
                }
                
removeLink Remove a link from the output of one node to the input of another node
from_name string the output node
from_port string the port indentifier of the output node
to_name string the input node
to_port string the port indentifier of the input node
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "removeLink",
                    "from_name": "Movie Reader",
                    "from_port": "out",
                    "to_name": "Yolo Classifier",
                    "to_port": "source",
                    "duration": 300,
                    "delay": 1000
                }
                
openViewer Displays the node's output in the viewer
node_name string the node to display
output_name string the port indentifier of the output node
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "openViewer",
                    "node_name": "Movie Reader",
                    "output_name": "out",
                    "duration": 300,
                    "delay": 1000
                }
                
closeViewer Closes the viewer
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "closeViewer",
                    "delay": 1000
                }
                
insertInput Inserts an input to a node
node_name string the node to display
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "insertInput",
                    "node_name": "And",
                    "duration": 300,
                    "delay": 1000
                }
                
removeInput Removes an input to a node
node_name string the node to display
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "removeInput",
                    "node_name": "And",
                    "duration": 300,
                    "delay": 1000
                }
                
openEditor Displays the node's output in the editor
node_name string the node to display
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "openEditor",
                    "node_name": "Movie Reader",
                    "duration": 300,
                    "delay": 1000
                }
                
closeEditor Closes the editor
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "closeEditor",
                    "delay": 1000
                }
                
editParameter Changes the value of the input of an edited node
node_name string the node to display
input_name string the port indentifier of the input node
value string the new value you wish to set the input parameter to
localizeValue bool [optional] use a localized version of the value
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "editParameter",
                    "node_name": "Yolo Classifier",
                    "input_name": "filter",
                    "value": "car",
                    "duration": 300,
                    "delay": 5000
                }
                
openPointOverlay Opens the edited input parameter point in the overlay
node_name string the node to display
input_name string the port indentifier of the input node
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "openPointOverlay",
                    "node_name": "Tracker Inference",
                    "input_name": "center",
                    "duration": 300,
                    "delay": 1000
                }
                
clickTrigger Clicks the trigger button of the edited input parameter
node_name string the node to display
input_name string the port indentifier of the input node
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "clickTrigger",
                    "node_name": "Tracker Inference",
                    "input_name": "start_stop",
                    "duration": 200,
                    "delay": 1000
                }
                
openRenderStatus Opens the render status window
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "openRenderStatus",
                    "duration": 200,
                    "delay": 1000
                }
                
closeRenderStatus Closes the render status window
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "closeRenderStatus",
                    "duration": 200,
                    "delay": 1000
                }
                
abortRenderStatus Aborts the render in the render status window
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "abortRenderStatus",
                    "duration": 200,
                    "delay": 1000
                }
                
nextVisualization Goes to the next visualization of the matrix in the viewer
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "nextVisualization",
                    "duration": 200,
                    "delay": 1000
                }
                
importWorkflow Goes to the next visualization of the matrix in the viewer
workflow string path of workflow to import
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "importWorkflow",
                    "workflow": "${demos}/PyTorch/CIFAR Classification/CIFAR Test/cifar test.json",
                    "delay": 1000
                }
                
clearWorkflow Clears the workflow
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "clearWorkflow",
                    "delay": 1000
                }
                
zoomFit Zooms the workflow viewport around the selected nodes
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "zoomFit",
                    "delay": 1000
                }
                
selectNode Selects a node in the workflow
node_name string the node to display
clear bool [optional] clears any prior selected nodes
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "selectNode",
                    "node_name" : "Add",
                    "delay": 1000
                }
                
togglePlay Toggles the playback between paused and playing
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "togglePlay",
                    "duration": 1000,
                    "delay": 2000
                }
                
firstFrame Goes to the first frame
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "firstFrame",
                    "duration": 1000,
                    "delay": 2000
                }
                
previousFrame Goes to the prior frame
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "previousFrame",
                    "duration": 1000,
                    "delay": 2000
                }
                
nextFrame Goes to the next frame
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "previousFrame",
                    "duration": 1000,
                    "delay": 2000
                }
                
lastFrame Goes to the last frame
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "lastFrame",
                    "duration": 1000,
                    "delay": 2000
                }
                
setCurrentFrame Sets the current frame
frame int the frame to jump to
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "setCurrentFrame",
                    "frame": 10",
                    "duration": 1000,
                    "delay": 2000
                }
                
click Clicks on a HTML element
id string the DOM element identifier
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "click",
                    "id": "#publish-workflow",
                    "duration": 1000,
                    "delay": 2000
                }
                
pan Pans the viewport of the workflow
dx float the delta x to pan
dy float the delta y to pan
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "pan",
                    "dx": 0,
                    "dy": 200,
                    "delay": 100
                }
                
openHyperparameters Opens the Hyperparameter dialog for a node
node_name string the name of the node
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "openHyperparameters",
                    "node_name" : "Logistic Regression",
                    "duration": 200,
                    "delay": 100
                }
                
closeHyperparameters Closes the Hyperparameter dialog
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "closeHyperparameters",
                    "duration": 200,
                    "delay": 100
                }
                
startGridSearch Starts a grid search for a node
node_name string the name of the node
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "startGridSearch",
                    "node_name" : "R2 Score",
                    "duration": 200,
                    "delay": 100
                }
                
openGridSearch Opens the Grid Search dialog
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "openGridSearch",
                    "duration": 200,
                    "delay": 100
                }
                
closeGridSearch Closes the Grid Search dialog
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "closeGridSearch",
                    "duration": 200,
                    "delay": 100
                }
                
optimizeGridSearch Selects to optimize in the Grid Search dialog
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "optimizeGridSearch",
                    "duration": 200,
                    "delay": 100
                }
                
openCreateMacro Opens the Create Macro Dialog
node_name string the name of the node
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "openCreateMacro",
                    "node_name" : "Sequential",
                    "duration": 200,
                    "delay": 100
                }
                
setMacroName Sets the Macro name in the Create Macro Dialog
macroName string the name of the macro
macroNotes string [optional] the nodes for the macro
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "macroName",
                    "macroName" : "MY CIFAR",
                    "delay": 100
                }
                
closeCreateMacro Closes the Create Macro Dialog and creates the macro
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "closeCreateMacro",
                    "duration": 200,
                    "delay": 100
                }
                
mergeCpuThreads Merges the nodes into same CPU thread
node_name string the name of the node
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "mergeCpuThreads",
                    "node_name" : "Canny",
                    "duration": 200,
                    "delay": 100
                }
                
splitCpuThreads Splits the nodes into into different CPU threads
node_name string the name of the node
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "splitCpuThreads",
                    "node_name" : "Canny",
                    "duration": 200,
                    "delay": 100
                }
                
setCudaDevice Sets the CUDA device for a node
node_name string the name of the node
duration int number of milliseconds to move the mouse to perform the operation
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "setCudaDevice",
                    "node_name" : "Brightness",
                    "duration": 200,
                    "delay": 100
                }
                
escapeToClose Press the escape key to close any open dialog
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "escapeToClose",
                    "delay": 100
                }
                
showImageUrl Shows an image in a popup window
url string the URL of the image
width string [optional] the width of the window
height int [optional] the height of the window
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "showImageUrl",
                    "url": "https://www.mdpi.com/sensors/sensors-19-04933/article_deploy/html/images/sensors-19-04933-g001.png",
                    "duration": 4000,
                    "width": 800,
                    "height": 800,
                    "delay": 1000
                }
                
showWebpage Shows an webpage in a popup iframe
url string the URL of the webpage
width string [optional] the width of the window
height int [optional] the height of the window
delay int [optional] number of milliseconds delay after which the task will be executed
    
                {
                    "name": "showWebpage",
                    "url": "https://docs.opencv.org/4.x/da/d22/tutorial_py_canny.html",
                    "duration": 4000,
                    "width": 800,
                    "height": 800,
                    "delay": 1000
                }
                

INFINICAM Quick Start Guide

01. Hardware Prep

Ensure lens and tripod are mounted, then connect the INFINICAM via high-quality USB 3.1 Type-C cable.

02. SDK Driver

Download the INFINICAM SDK, unzip, right-click phrtcam.inf, and select Install.

03. Device Verification

Confirm "Photron USB3.0 Real Time Camera" is detected in Device Manager.

04. Download Workflow

Get infiniworkflow_v1_0.zip from the Photron dev portal and unzip to your Documents folder.

05. Run Installer

Execute install.bat (Windows) or sudo sh install.sh (Linux/OSX) with admin privileges.

06. Wait for Build

Allow the installer to finish configuring Python modules and Firewall access (5–30 min).

07. Launch App

Run INFINIWORKFLOW.bat or sh INFINIWORKFLOW.sh to start the local server.

08. Open Browser

Use Chrome (131.0+) to open the local interface URL.

09. Load Hub

Click the HUB icon to view system diagnostics and available tools.

10. Start Tutorial

Select a "Live Tutorial" from the Help menu to begin.

11. Add INFINICAM Node

Node Drag and Drop

Open the Photron category and drag the INFINICAM node onto your workspace.

12. Apply Canny Edge

Node Drag and Drop

Search for Canny Edge in the toolbox and connect its input to the INFINICAM node's output port.

13. View & Edit

View and Edit

Drop View and Edit nodes onto the canvas to visualize and refine your pipeline.

14. Advanced Details

Check the full documentation for deep dives into detection parameters and data saving configurations.

View Infinicam Section →