Skip to content

Writing Custom Scripts

This module facilitates the execution of Python script functions during acquisition. For the scripts to work, they must adhere to the templates provided in the inscoper-scripts repository.

Image Provider Function Architecture

The image provider function acts as your script's entry point. The acquisition engine invokes this function after every image capture event. Its responsibilities are:

  1. Execution Gatekeeping: Evaluating whether the processing function should run (e.g., waiting until a Z-stack is completed).
  2. Image Selection: Deciding which images to fetch from memory and pass to the processing function (e.g., passing the full Z-stack array versus isolating the final 2D frame).

Signature

Arguments

  • new_image (images): The function expects a primary argument defined with type images. It receives the last image acquired by the hardware. This object contains the metadata required to identify the microscope's multidimensional state (Time, Position, Channel, and Z-slice indices).
  • Optional Parameter Arguments: You can define additional parameters (such as channel_index, focus_option) which the user will configure within the GUI.

Return Value

The Image Provider function is structurally required to return a List[Dict[str, int]].

  • Empty List [] or None: Returning an empty array signals the engine to SKIP the processing function for the current iteration.
  • Populated List of Dictionaries: Instructs the system to EXECUTE the processing function. Each dictionary specifies an image to fetch from memory.

    • Empty Dictionary {}: Fetches the current image (indices are inferred from the new_image object).
    • Specific Indices (e.g., {'focusIndex': 3}): Fetches an image from a specific coordinate (e.g., Z-slice 3). Any dimension index not explicitly declared (e.g., timeIndex, positionIndex) is copied from the current new_image.
    Architectural Dimension Dimension Key (index) Dimension Size Attribute (sizeDim)
    Time (t) timeIndex timeSize
    Position (XY) positionIndex positionSize
    Channel (λ) channelIndex channelSize
    Focus (Z) focusIndex focusSize
    Lifetime (FLIM) flimIndex flimSize

Code Example: Fetching an Entire Z-stack

This example checks if the current image is the absolute final slice of a Z-stack. If so, it collects all prior slices so that the Imaging Software can dispatch this list of images to the processing function; if not the final slice, it does nothing and awaits the next capture. Note that the positionIndex and timeIndex are inferred from the new_image object.

from inscoper_scripts.utils import extract_metadata
import numpy as np
from typing import List, Dict

def fetch_zstack(new_image: "images", channel_index: int = 0) -> List[Dict[str, int]]:
    """
    Collect the entire volumetric Z-stack for the current spatial position at the logically defined target channel.
    """
    # 1. Analytically extract the metadata dictionary from the current image object
    meta = extract_metadata(new_image)

    current_z = meta.get('focusIndex', 0)
    total_z = meta.get('focusSize', 1)

    # 2. Evaluate physical conditions: Only authorize execution at the final mechanical Z slice
    if current_z != (total_z - 1):
        return [] # Return empty array to skip computationally expensive processing

    # 3. Construct chronological selection: All volumetric slices (0 to total_z-1)
    # We deliberately only specify 'focusIndex' and 'channelIndex'. 
    # 'timeIndex' and 'positionIndex' are reliably inferred from the current image state.
    image_selection = []
    for z in range(total_z):
        image_selection.append({
            'focusIndex': z,
            'channelIndex': channel_index
        })

    return image_selection

Code Example: Fetching the Singular Current Image

This represents the simplest case. Returning a list containing a single empty parameter dictionary instructs the engine to send solely the current image to the processing function.

def fetch_current_image(new_image: "images") -> List[Dict[str, int]]:
    return [{}]

Code Example: Fetching the Last Two Distinct Timepoints

This specific pattern retrieves the image from both the previous (t-1) and the current (t) timepoints. This is useful for tracking algorithms.

def fetch_last_two_timepoints(new_image: "images") -> List[Dict[str, int]]:
    meta = extract_metadata(new_image)
    current_t = meta.get('timeIndex', 0)

    # Logical Gate: We require a minimum of 2 discrete timepoints (Index 0 and Index 1) to proceed
    if current_t < 1:
        return []

    return [
        {'timeIndex': current_t - 1}, # Request previous chronological timepoint
        {'timeIndex': current_t}      # Request current, active timepoint
    ]

Processing Function Architecture

Within the data processing function, the primary argument must be designated as images. This variable receives the list of image arrays returned by the image provider, serving as the dataset for your algorithms.

Supported Argument Types and UI Automation

Standard Python Type Automatically Generated Graphical Interface Functional Description
str A standard string parameter, rendered identically as a text input field.
int An integer value, rendered as a numeric spin box with a fixed increment constraint of 1.
float A floating-point value, rendered as a precise numeric spin box with a standardized increment of 0.001.
bool A binary boolean value, rendered as a visual toggle switch.
Path or str with / or \\ A path directly to a file directory, rendered as a system directory chooser widget.
Literal["val1", "val2", "val3"] A value constrained by an enumeration, rendered as an exclusive dropdown list.
List[Literal["val1", "val2", "val3"]] A list of values constrained by an enumeration, rendered as a multi-selection dropdown list.
images Represents one or more image arrays provided by the Imaging Software (the last acquired image for the image provider function, or a curated list of images for the processing function).
SubDeviceId A sub-device name (used as a key to read its value in the metadata), rendered as a dropdown list of all available sub-devices.
channel A channel name, rendered as a dropdown list of all available channels.
IIS_CONTEXT A context object, allowing the script to interact with the software environment (variable transfer, method execution).

Initial default logic values can be initialized directly inside the function signature header, adhering to standard Python typing conventions: e.g., var1: float = 0.5 or List[Literal["val1", "val2", "val3"]] = ["val2"].

Utilizing the Imaging Software Context Engine (IIS_CONTEXT)

The IIS_CONTEXT exposes methods allowing your script to interact with the software environment.

getCameras()

Retrieves a list of active cameras.

  • Return Signature: List[str] - An array list containing valid camera identifier strings.

Functional Example:

cameras = IIS_CONTEXT.getCameras()
# Programmatic return evaluation: ["Camera1", "Camera2"]

getProjectPath()

Retrieves the path of the currently active project directory.

  • Return Signature: str - The string representing the active project path.

Functional Example:

path = IIS_CONTEXT.getProjectPath()
# Programmatic return evaluation: "D:/Data/Project_001"

displayImage(id, img)

Sends an image array to render directly into a designated data processor within the visualization dashboard.

  • Parameters:
    • id (str): An identifier matching the target data processor.
    • img (NDArray): The raw image data payload to view.

setVariable(id, value)

Caches a variable within the application's shared memory architecture. This function is useful to pass global variables during the acquisition loop.

  • Parameters:
    • id (str): The string key utilized to identify the cached variable.
    • value (Object): The data value intended to be stored.

Functional Example:

IIS_CONTEXT.setVariable("tracking_counter", 1)

getVariable(id)

Retrieves a variable previously cached utilizing the setVariable method.

  • Parameters:
    • id (str): The string key corresponding to the desired variable.
  • Return Signature: object - The currently cached value.

Functional Example:

count = IIS_CONTEXT.getVariable("tracking_counter")

fireOnDemand(cameraName, roi, channelName, powerMap, repetition)

Triggers a FRAP photo-activation sequence along the defined region of interest (ROI) using the specified channel and power parameters.

  • Parameters:
    • cameraName (str): The name of the camera to be used for the photo-activation sequence (this string must exactly match one of the returned values from the getCameras() execution).
    • roi (Object): The geometric region of interest. It functionally requires an ROI programming instance (e.g., RectangleROI) or an extended array list containing such precise instances imported from the system's inscoper_scripts.utils.rois core module. If an array list is structurally provided, the system sequentially, mechanically photoactivates each ROI.
    • channelName (str): The definitive channel configuration nomenclature to utilize.
    • powerMap (Object): The physical hardware Illumination/Power settings formatted algorithmically as a Python dictionary structure (e.g., {"MyLaserSubDevice": 100}).
    • repetition (Object): The numerical repetition parameters (e.g., configuring 10 forces exactly 10 consecutive hardware cycles).

Functional Example:

from inscoper_scripts.utils.rois import RectangleROI

# Objectively define structural parameters
cam = "Camera1"
my_roi = RectangleROI(0, 0, 512, 512, fill=False)
channel = "GFP_Activation"
power = {"488nm_Laser": 50.0}
reps = 1

# Issue command to mechanically trigger sequence acquisition
IIS_CONTEXT.fireOnDemand(cam, my_roi, channel, power, reps)