pyimagej-fiji-bridge
Python bridge to ImageJ2/Fiji for macros, plugins (Bio-Formats, TrackMate, Analyze Particles), NumPy↔ImagePlus/ImgLib2 exchange, and ImageJ Ops. Automates Fiji headlessly from Python. Use scikit-image for pure Python without Fiji plugins; napari for visualization.
Install / Use
npx skills add jaechang-hits/SciAgent-Skills --skill pyimagej-fiji-bridgeInstalls into whichever agent you are using.
SKILL.md
Installable skill definition
Quality Score
Category
AutomationSupported Platforms
Our assessment of pyimagej-fiji-bridge
pyimagej-fiji-bridge scores 91/100 on our quality scale, 1091st of 2,866 Automation skills we index (top 39%).
Its SKILL.md is 24 KB long, well organised into 60 sections with 17 code examples: a thorough specification that gives an agent plenty to work with.
It has 367 GitHub stars, a meaningful sign that others use it.
Maintenance, license and trust
- The repository was last updated 37 days ago, so pyimagej-fiji-bridge is actively maintained.
- No license is declared. By default that means all rights are reserved: you can read it, but reusing or redistributing it is not clearly permitted. Ask the author before building on it commercially.
- Its trust signals score 88/100, with 1 caution from licensing, adoption, age or documentation. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.
Safety scan
No issues foundOur scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands.
Automated pattern scan on 2026-10-05. It catches known dangerous patterns, not every risk — read a skill before letting an agent act on it.
pyimagej-fiji-bridge compared with similar skills
All 4 of these similar skills score higher than pyimagej-fiji-bridge; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| pyimagej-fiji-bridge (this skill)by jaechang-hits | 91 | 367 | 37d ago | SKILL.md |
| Agent-Reachby Panniantong | 100 | 90.8k | 19d ago | CLAUDE.md |
| headroomby headroomlabs-ai | 100 | 74.4k | today | CLAUDE.md |
| Scraplingby D4Vinci | 100 | 85.7k | today | MCP Server |
| crawl4aiby unclecode | 100 | 84.8k | 9d ago | MCP Server |
Frequently asked questions
- How do I install pyimagej-fiji-bridge?
- Run
npx skills add jaechang-hits/SciAgent-Skills --skill pyimagej-fiji-bridge. The install tabs above show the steps for each supported agent. - Which AI agents does pyimagej-fiji-bridge work with?
- It is written for Universal, as a SKILL.md file. Other agents that read the same format can often use it too.
- Is pyimagej-fiji-bridge safe to use?
- Our scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. It declares no license and scores 88/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is pyimagej-fiji-bridge still maintained?
- The repository was last updated 37 days ago, so pyimagej-fiji-bridge is actively maintained.
Skill content
View source on GitHubname: "pyimagej-fiji-bridge" description: "Python bridge to ImageJ2/Fiji for macros, plugins (Bio-Formats, TrackMate, Analyze Particles), NumPy↔ImagePlus/ImgLib2 exchange, and ImageJ Ops. Automates Fiji headlessly from Python. Use scikit-image for pure Python without Fiji plugins; napari for visualization." license: "Apache-2.0"
PyImageJ — Python Bridge to ImageJ/Fiji
Overview
PyImageJ provides a Python interface to ImageJ2 and Fiji through PyJNIus and scyjava, embedding a full Java Virtual Machine inside a Python process. It enables bidirectional data exchange between NumPy arrays and ImageJ's ImagePlus/ImgLib2 data structures, so you can preprocess images in Python, pass them into Fiji plugins (Bio-Formats, TrackMate, Analyze Particles, Weka segmentation), and return results back to pandas DataFrames. The library supports headless operation for scripting and batch processing, as well as GUI mode for interactive Fiji sessions.
When to Use
- Running Fiji-specific plugins from Python: Bio-Formats multi-format I/O, TrackMate particle tracking, CLIJ2 GPU processing, or community Fiji update site plugins
- Automating ImageJ macro pipelines headlessly without opening the Fiji GUI, e.g., batch processing an entire experiment overnight
- Applying the ImageJ Ops framework (150+ image processing operations) with the full ImageJ type system
- Converting between NumPy arrays (SciPy ecosystem) and ImageJ hyperstacks (TZCYX channel order) for round-trip processing
- Parsing ImageJ Results tables and ROI Manager measurements into pandas DataFrames for downstream statistical analysis
- Executing existing
.ijmmacro files as part of a Python workflow without rewriting them - Use
scikit-imageinstead when you need pure Python processing without Fiji plugins — scikit-image is faster to install and avoids JVM overhead - Use
napariinstead for interactive multi-dimensional image visualization and annotation; PyImageJ does not replace a viewer
Prerequisites
- Python packages:
pyimagej,scyjava,numpy,pandas - Java: Java 8 or Java 11 (Java 17 is not supported); use conda for reliable Java management
- Fiji/ImageJ2: Downloaded automatically on first init, or specify a local Fiji installation path
- Environment: conda environment strongly recommended; pip-only installs often have JVM path issues
# Recommended: conda installation
conda create -n pyimagej -c conda-forge pyimagej openjdk=11
conda activate pyimagej
# Install additional dependencies
pip install pandas tifffile
# Verify
python -c "import imagej; ij = imagej.init('sc.fiji:fiji', mode='headless'); print(ij.getVersion())"
Quick Start
import imagej
import numpy as np
# Initialize Fiji in headless mode (downloads on first run, ~500 MB)
ij = imagej.init("sc.fiji:fiji", mode="headless")
print(f"ImageJ version: {ij.getVersion()}")
# Create a test image, process with Gaussian blur via Ops, convert back
arr = np.random.randint(0, 1000, (256, 256), dtype=np.uint16)
imp = ij.py.to_imageplus(arr)
blurred = ij.op().filter().gauss(imp.getProcessor(), 2.0)
result = ij.py.from_imageplus(imp)
print(f"Processed array shape: {result.shape}, dtype: {result.dtype}")
Core API
Module 1: Initialization
PyImageJ must be initialized once per Python session. The mode and endpoint determine which ImageJ distribution and GUI behavior to use.
import imagej
# Headless Fiji — most common for scripts and batch jobs
ij = imagej.init("sc.fiji:fiji", mode="headless")
# GUI mode — opens the Fiji window (requires a display)
ij = imagej.init("sc.fiji:fiji", mode="gui")
# Local Fiji installation — faster startup, no download
ij = imagej.init("/path/to/Fiji.app", mode="headless")
# Specific Fiji version
ij = imagej.init("sc.fiji:fiji:2.14.0", mode="headless")
# Bare ImageJ2 without Fiji plugins
ij = imagej.init("net.imagej:imagej", mode="headless")
print(f"ImageJ version: {ij.getVersion()}")
print(f"Headless: {ij.ui().isHeadless()}")
Module 2: Image I/O
Open and save images using ImageJ's I/O layer (which includes Bio-Formats for proprietary formats) and convert between ImageJ and NumPy representations.
import imagej
import numpy as np
ij = imagej.init("sc.fiji:fiji", mode="headless")
# Open any format Bio-Formats supports: CZI, LIF, ND2, ICS, TIFF, etc.
imp = ij.io().open("/data/experiment.czi")
print(f"Dimensions: {imp.getDimensions()}") # [W, H, C, Z, T]
print(f"nSlices: {imp.getNSlices()}, nFrames: {imp.getNFrames()}")
# Save image
ij.io().save(imp, "/data/output.tif")
print("Saved output.tif")
# NumPy ↔ ImageJ conversion
arr = np.zeros((100, 100), dtype=np.uint16)
arr[30:70, 30:70] = 1000 # bright square
# NumPy → ImagePlus
imp = ij.py.to_imageplus(arr)
print(f"ImagePlus: {imp.getWidth()}×{imp.getHeight()}, type={imp.getType()}")
# ImagePlus → NumPy (returns a view where possible)
arr_back = ij.py.from_imageplus(imp)
print(f"NumPy array: shape={arr_back.shape}, dtype={arr_back.dtype}")
# Multi-channel array: shape (C, H, W)
rgb = np.random.randint(0, 255, (3, 256, 256), dtype=np.uint8)
imp_rgb = ij.py.to_imageplus(rgb)
print(f"Channels: {imp_rgb.getNChannels()}")
Module 3: Macro Execution
Run ImageJ macro language (IJM) snippets or macro files. Macros execute inside the ImageJ environment and can call any built-in ImageJ command.
import imagej
ij = imagej.init("sc.fiji:fiji", mode="headless")
# Run an inline macro string
ij.macro.run("print('Hello from ImageJ macro');")
# Run a macro with options string (key=value pairs)
# Options string mirrors the dialog parameters of ImageJ commands
macro_code = """
run("Gaussian Blur...", "sigma=2");
run("Auto Threshold", "method=Otsu white");
"""
ij.macro.run(macro_code)
# Run a macro file from disk
ij.macro.runMacroFile("/scripts/my_analysis.ijm")
# Run macro that returns a value via getResult or output string
result = ij.macro.run("""
x = 42 * 2;
return x;
""")
print(f"Macro returned: {result}")
# Macro with current image: open → process → measure
ij.io().open("/data/cells.tif") # sets current active image
measure_macro = """
run("Set Measurements...", "area mean min integrated redirect=None decimal=3");
run("Analyze Particles...", "size=50-Infinity display clear summarize");
"""
ij.macro.run(measure_macro)
print("Analyze Particles complete; results in Results table")
Module 4: ImageJ Ops
ImageJ Ops is a framework of 150+ image processing operations with type-safe dispatch. Ops work on ImgLib2 Img objects and are the preferred way to call image processing algorithms programmatically.
import imagej
import numpy as np
ij = imagej.init("sc.fiji:fiji", mode="headless")
arr = np.random.randint(100, 900, (512, 512), dtype=np.uint16)
img = ij.py.to_java(arr) # converts to ImgLib2 RandomAccessibleInterval
# Gaussian blur
blurred = ij.op().filter().gauss(img, 2.0)
blurred_np = ij.py.from_java(blurred)
print(f"Blurred: {blurred_np.shape}")
# Otsu threshold → binary image
binary = ij.op().threshold().otsu(img)
binary_np = ij.py.from_java(binary)
print(f"Binary unique values: {np.unique(binary_np)}")
# Morphological operations
from jnius import autoclass
BitType = autoclass("net.imglib2.type.logic.BitType")
opened = ij.op().morphology().open(binary, [3, 3])
opened_np = ij.py.from_java(opened)
print(f"After opening: {opened_np.shape}")
# Statistics ops
mean_val = ij.op().stats().mean(img)
std_val = ij.op().stats().stdDev(img)
print(f"Mean intensity: {mean_val:.1f}, StdDev: {std_val:.1f}")
# Math ops: multiply image by scalar
scaled = ij.op().math().multiply(img, ij.py.to_java(2.0))
print(f"Scaled max: {ij.py.from_java(scaled).max()}")
Module 5: Plugin and Command Calls
SciJava commands are the primary way to invoke Fiji plugins programmatically. Commands accept a dict of named parameters mirroring the plugin dialog.
import imagej
ij = imagej.init("sc.fiji:fiji", mode="headless")
# Open a file using Bio-Formats opener command
future = ij.command().run(
"loci.plugins.LociImporter",
True,
{"id": "/data/image.lif", "open_files": True, "autoscale": True}
)
module = future.get()
imp = module.getOutput("imp")
print(f"Opened via Bio-Formats: {imp.getDimensions()}")
# Run Analyze Particles as a SciJava command
ij.io().open("/data/binary_mask.tif")
future = ij.command().run(
"ij.plugin.filter.ParticleAnalyzer",
True,
{
"minSize": 50.0,
"maxSize": float("inf"),
"options": 0, # SHOW_NONE
"measurements": 1, # AREA
}
)
future.get()
print("Analyze Particles command complete")
# Alternatively, run via macro string for simpler plugin invocation
ij.macro.run("""
run("Analyze Particles...", "size=50-Infinity display clear summarize");
""")
Module 6: Results Table and ROI Analysis
Retrieve measurement results from ImageJ's Results table and ROI Manager after running Analyze Particles or other measurement commands.
import imagej
import pandas as pd
ij = imagej.init("sc.fiji:fiji", mode="headless")
# After running Analyze Particles, read the Results table
def results_to_dataframe(ij) -> pd.DataFrame:
"""Convert ImageJ Results table to pandas DataFrame."""
rt = ij.ResultsTable.getResultsTable()
if rt is None or rt.size() == 0:
return pd.DataFrame()
headings = list(rt.getHeadings())
data = {col: [rt.getValue(col, i) for i in range(rt.size())]
for col in headings}
return pd.DataFrame(data)
# Run segmentation + measurement macro
ij.io().open("/data/cells.tif")
ij.macro.run("""
run("Gaussian Blur...", "sigma=1.5");
setAutoThreshold("Otsu dark");
run("Convert to Mask");
run("Analyze Particles...", "size=20-Infinity display clear");
""")
df = results_to_dataframe(ij)
print(f"Found {len(df)} objects")
print(df[["Area", "Mean", "IntDen"]].describe())
df.to_csv("particle_measurements.csv", index=False)
print("Saved particle_measurements.csv")
# Access the ROI Manager
def get_roi_manager(ij):
"""Return the ImageJ ROI Manager instance, creating if needed."""
RoiManager = ij.py.jclass("ij.plugin.frame.RoiManager")
rm = RoiManager.getInstance()
if rm is None:
rm = RoiManager(False) # headless=False means no GUI window
return rm
rm = get_roi_manager(ij)
roi_count = rm.getCount()
print(f"ROIs in manager: {roi_count}")
# Extract bounding boxes for all ROIs
rois = []
for i in range(roi_count):
roi = rm.getRoi(i)
bounds = roi.getBounds()
rois.append({"index": i, "x": bounds.x, "y": bounds.y,
"width": bounds.width, "height": bounds.height})
roi_df = pd.DataFrame(rois)
print(roi_df.head())
Common Workflows
Workflow 1: Automated Fluorescence Quantification
Goal: Open a multi-channel TIFF stack, apply Gaussian blur, threshold nuclei channel, run Analyze Particles, and export per-cell measurements as CSV.
import imagej
import pandas as pd
import numpy as np
from pathlib import Path
ij = imagej.init("sc.fiji:fiji", mode="headless")
def quantify_nuclei(tiff_path: str, output_csv: str,
channel: int = 1, sigma: float = 1.5,
min_size: int = 50) -> pd.DataFrame:
"""
Segment and measure nuclei in a fluorescence TIFF.
Parameters
----------
tiff_path : path to single- or multi-channel TIFF
output_csv : where to save results
channel : 1-based channel index for nuclear stain (e.g., DAPI)
sigma : Gaussian blur radius in pixels
min_size : minimum nucleus area in pixels
"""
# Step 1: Open image
imp = ij.io().open(tiff_path)
print(f"Loaded: {Path(tiff_path).name} dims={imp.getDimensions()}")
# Step 2: Extract channel if multi-channel
if imp.getNChannels() > 1:
imp.setC(channel)
# Step 3: Apply Gaussian blur and threshold via macro
ij.macro.ru
Truncated for display — read the full file on GitHub.
Related Skills
Agent-Reach
90.8kGive your AI agent eyes to see the entire internet. Read & search Twitter, Reddit, YouTube, GitHub, Bilibili, XiaoHongShu — one CLI, zero API fees.
headroom
74.4kCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.
Scrapling
85.7k🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl! Don't be shy, join here: https://discord.gg/EMgGbDceNQ and follow here for daily tips and tricks: https://x.com/Scrapling_dev
crawl4ai
84.8kOpen-source web crawler and scraper for LLMs and AI agents: any website into clean, LLM-ready Markdown. Run it yourself, or use Crawl4AI Cloud with one key.
Languages
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.
