Object Intensity Profiling is an ImageJ/Fiji plugin for measuring where raw signal lies inside each object in a label image. It provides fixed-length radial, image-axis, principal-axis, angular and shell profiles; per-object cross-channel correlation; and optional texture measurements. Normal interactive runs show the object tables and aggregate profile plots; auto-save is optional.
The label image supplies object geometry only. Label pixels must be zero (background) or exact positive integers; fractional, negative, non-finite, and out-of-range values are rejected. Supply one to four dimension-matched raw images and explicitly choose the reference signal for Pearson, overlap and Manders measurements. Raw channel names must be nonblank and distinct on a case-insensitive filesystem.
- Radial, marginal X/Y/Z, principal-axis, angular and concentric-shell intensity profiles.
- Object-mask sampling by default, with a padded bounding-box option.
- Per-object Pearson correlation, overlap coefficient, and Manders M1/M2.
- Optional 2D grey-level co-occurrence matrix (GLCM) measurements: contrast, angular second moment (energy), correlation, entropy and homogeneity.
- Optional eight-feature Gabor/wavelet texture classes using deterministic k-means clustering.
- Optional intensity-weighted Zernike moments (magnitude and phase up to a chosen degree) of each object's maximum-intensity projection.
- Optional profile-shape classes: objects grouped by the shape of one normalised curve (radial by default) with the same deterministic k-means, fitted once across a whole folder batch.
- Fixed GLCM quantisation per channel across a folder batch, with optional manual per-channel limits.
- Per-object CSV files, object-weighted aggregate curves with standard error, aggregate figures and class-coloured maps.
- Interactive, ImageJ macro and headless Java entry points.
| Question | Measurement |
|---|---|
| Is the signal concentrated in the centre or at the edge of each object? | Radial profile, shell profile |
| Is the signal lopsided along the image axes or the object's own long axis? | Marginal X/Y/Z and principal-axis profiles |
| Does the signal form a complete ring or only an arc? | Angular profile and ring completeness |
| Do two channels rise and fall together inside each object? | Pearson, overlap and Manders M1/M2 |
| Is the signal smooth, grainy or striped inside each object? | GLCM features, texture classes |
| What 2D shape does the signal make inside each object? | Zernike moments |
| Which objects share the same profile shape? | Profile-shape classes |
In Fiji, choose Help > Update... > Manage update sites, add an update site
named Object-Intensity-Profiling with this URL, and enable it:
https://sites.imagej.net/Object-Intensity-Profiling/
Apply the changes and restart Fiji. The command is then available at
Plugins > Object Intensity Profiling.
Requirements: Fiji (ImageJ 1.54 or newer) with Java 8 or newer. No other update
sites are needed; the shared oc3d-core classes are inside the plugin jar.
Object Intensity Profiling uses oc3d-core 0.1.0 for shared recursive
regular-expression batch discovery. The core is not published to a Maven
repository, so install that pinned release into the local Maven repository
before building the plugin:
git clone --branch v0.1.0 https://github.com/Jay2owe/oc3d-core
mvn -f oc3d-core/pom.xml clean install
Then run:
# macOS/Linux
./mvnw clean verify
# Windows
mvnw.cmd clean verify
The plugin JAR is written to
target/Object_Intensity_Profiling-0.3.1.jar.
The reachable core classes are included under oip.internal.core; users copy
only the plugin JAR into Fiji and do not install the core separately.
Copy that JAR into Fiji's plugins/ folder and restart Fiji. The command is
then available at Plugins > Object Intensity Profiling.
- Open one label image (or keep an ImageJ ROI set file to hand) and one to four raw images with identical width, height and slice count.
- Run
Plugins > Object Intensity Profiling. - Choose Open images or Folder batch.
- Choose the correlation reference raw channel.
- Leave texture options disabled unless they are needed; they are the slow part of the analysis.
A single-image auto-save contains Profiles/, Texture/, Aggregate/,
Figures/, and Maps/. A batch root contains Aggregate/, Figures/, and
Samples/; each current sample has the complete five-directory tree beneath
Samples/<sample>/. A plugin-owned manifest safely removes sample folders
that disappear on a later successful rerun while preserving unrelated files
elsewhere in the output tree. A rerun replaces a plugin-owned
Samples/<sample>/ folder in full, so do not keep your own files inside one.
Each generated sample also contains an ownership marker; both the marker and
the manifest entry must validate before an existing directory can be moved.
Manifest identities are compared case-insensitively so case-only sample
renames rerun correctly on Windows.
If a current sample name collides with an existing folder that is not in that
manifest, the run stops without replacing the folder.
The complete batch is written to an isolated staging tree and promoted only
after every sample and combined output succeeds, so cancellation or failure
leaves the previous live batch unchanged.
Linked or redirected output containers are rejected before any live path is
moved. Exact figure and class-map manifests ensure cleanup removes only files
generated by this plugin, even when unrelated filenames begin with OIP_.
Manifest updates use unique temporary files, and recursive batch discovery
rejects linked directories and directory cycles.
Minimal single-channel call:
run("Object Intensity Profiling",
"labels=[Objects] raw1=[DAPI] reference=[DAPI]");
Multi-channel call:
run("Object Intensity Profiling",
"labels=[Objects] raw1=[DAPI] raw1_name=[DAPI] " +
"raw2=[Marker] raw2_name=[Marker] reference=[DAPI] " +
"radial marginal principal angular shell correlation mask " +
"no_glcm no_texture_classes radial_bins=20 curve_bins=50 " +
"angular_bins=12 shells=3 padding=0");
Use labels_path, raw1_path ... raw4_path for images that are not
already open.
Objects can come from an ImageJ ROI set instead of a label image, and an optional region ROI set can restrict which objects are profiled:
run("Object Intensity Profiling",
"objects_roi=[C:/data/cells.zip] raw1_path=[C:/data/dapi.tif] " +
"region_roi=[C:/data/scn.roi]");
objects_roireads a.zipROI set (as saved by the ROI Manager) or a single.roifile and turns it into a label image the size ofraw1, with its calibration. ROI 1 in the file becomes label 1, ROI 2 label 2, and so on; theSourcecolumn is the ROI file name without its extension. An ROI with a Z position (Properties... or the ROI Manager's slice) is drawn on that slice only; an ROI without one is drawn on every slice, as a column through the stack. Where ROIs overlap, the later ROI in the file owns the shared pixels, so an ROI completely covered by a later one leaves no object. Every ROI must enclose an area: line, angle and point selections, empty ROIs, ROIs outside the image and ROIs positioned beyond the last slice are rejected with a message naming the ROI.region_roikeeps only objects whose centroid lies inside the union of the region's area ROIs. The centroid is tested at its nearest pixel (halves round up) on its nearest slice, and a region ROI with a Z position applies to that slice only, following the same rule as object ROIs. Line or point region ROIs are rejected, and a region that contains no object centroid stops the run with a message naming the ROI file.- In the Open images dialog, choose Objects from: ROI set file and pick the file; the region ROI set is an optional file field.
- Folder batches do not take ROI inputs in this version; convert each ROI set to a label image first or run the images one at a time.
From Java, OipRoiInputs.labelsFromRoiSet(reference, path) returns the label
image and OipParameters.Builder.regionRois(Roi[]) sets the region. Add auto_save output=[C:/analysis/OIP] hide_display for a
headless run. Manual GLCM limits use paired options such as
quant_min1=0 quant_max1=65535.
| Option | Default | Meaning |
|---|---|---|
labels / labels_path |
required | Open label-image title or file path |
objects_roi |
— | ROI set (.zip or .roi) defining the objects instead of labels; see ROI inputs |
region_roi |
all objects | ROI set; keep only objects whose centroid lies inside it |
raw1 ... raw4 / rawN_path |
raw1 required |
Open raw-image title or file path |
rawN_name |
image title | Stable output/API channel name |
reference |
sole raw channel | Correlation reference; required with multiple raw channels |
radial, marginal, principal, angular, shell, correlation |
enabled | Enable profile families |
no_radial, no_marginal, no_principal, no_angular, no_shell, no_correlation |
— | Disable a default profile family |
mask / box |
mask |
Restrict sampling to object voxels or use the padded box |
intensity_norm |
minmax |
Aggregate-curve normalisation: minmax, mean, or zscore |
radial_bins, curve_bins, angular_bins, shells |
20, 50, 12, 3 |
Profile resolution |
padding |
0 |
Bounding-box padding percentage |
ring_threshold |
50 |
Percent of the angular-profile maximum counted as present |
reference_threshold, partner_threshold |
0, 0 |
Manders M2 and M1 presence thresholds, respectively |
glcm, texture_classes |
disabled | Enable slow texture families |
glcm_levels, glcm_distance |
32, 1 |
GLCM grey levels and pixel offset |
texture_k |
4 |
Number of texture classes |
minimum_texture_voxels |
64 |
Suppress texture below this object size |
zernike / no_zernike |
disabled | Write Zernike moments to Profiles/Object_Zernike.csv |
zernike_degree |
9 |
Highest Zernike order n, 1 to 20 (9 gives 30 moments) |
profile_classes / no_profile_classes |
disabled | Write profile-shape classes to Profiles/Profile_Classes.csv and class-mean curves to Aggregate/Profile_Class_Curves.csv |
profile_k |
4 |
Number of profile-shape classes, 1 to 255 |
profile_class_type |
radial |
Curve used for the classes: radial, shell, angular, pc_major, marginal_x or marginal_y |
quant_minN, quant_maxN |
automatic | Manual fixed GLCM range for raw channel N |
save_figures / no_figures |
save | Save or suppress aggregate figures |
save_maps / no_maps |
save | Save or suppress texture class maps |
auto_save output=[...] |
disabled | Write the complete output tree |
hide_display |
disabled | Do not show result tables or maps |
source_name |
label image title | Name written to the Source output column |
auto_save, output and hide_display also accept the aliases autosave,
save_dir and no_display. Any option outside this table is rejected rather
than ignored, and so is an option given twice (raw1= twice) or given with
its opposite (glcm no_glcm, mask box, output=... save_dir=...), rather
than letting the last one win.
When a macro fails (unknown option, missing image, wrong dimensions), the
reason is written to the Log window as one line and shown in an error
message, and the macro stops at that line. In a headless run (--headless)
there is no message window: the one-line reason goes to the log (the console)
and the macro stops, but Fiji still exits with code 0, so a script that runs
Fiji headless should check that its expected output files exist rather than
rely on the exit code.
Headless Java or script callers get the one-line reason as an exception.
Results of a headless run are saved but never displayed. Two
open images with the same title are rejected, because the recorded macro could
not tell them apart: rename one first.
Interactive count and bin fields require exact whole numbers; fractional entries are rejected rather than silently truncated.
Image-title options require the images to be open. Path options open and close their images internally. Macro and Java API execution do not open interactive dialogs.
Batch options begin with batch. This runs without file choosers or
confirmation dialogs:
run("Object Intensity Profiling",
"batch labels_folder=[C:/data/labels] " +
"labels_regex=[(.*)_labels\\.tif] " +
"raw1_name=[DAPI] raw1_folder=[C:/data/raw] " +
"raw1_regex=[(.*)_dapi\\.tif] reference=[DAPI] " +
"output=[C:/analysis/OIP] recursive mask radial marginal principal " +
"angular shell correlation no_glcm no_texture_classes " +
"save_figures save_maps hide_display");
For raw slots 1 to 4, use rawN_name, rawN_folder, and rawN_regex
together. labels_folder, labels_regex, and output are required.
Every label and raw channel must resolve to the same set of sample keys;
missing labels, missing raws, and orphan raw files are rejected.
The only batch-only flag is recursive / no_recursive. All profile, texture, threshold,
bin, padding, and quant_minN / quant_maxN options in the table above also
apply to batch mode, and are parsed by the same code in both modes.
| Option | Single image | Folder batch |
|---|---|---|
labels, labels_path, rawN, rawN_path |
inputs | rejected; use labels_folder, labels_regex, rawN_name, rawN_folder, rawN_regex |
labels_folder, labels_regex, rawN_folder, rawN_regex, recursive |
rejected; start the options with batch |
inputs |
output / save_dir |
output folder, used with auto_save |
required output folder |
auto_save / autosave |
write the output tree | accepted and ignored: a batch always saves |
source_name |
name for the Source column |
rejected: batch sources are always Labels, and each sample is named by capture group 1 of labels_regex |
| in that channel; a complete manual min/max pair replaces that scan only for | ||
| its channel. Manual limits are rejected when their numbered raw slot is not | ||
| configured. | ||
| Pairing preview opens each matched image once to reject incompatible | ||
| dimensions or channel/slice/time layouts before quantisation or analysis. | ||
| It also rejects all-background label images before any range scan or output, | ||
| listing every empty sample in one message. | ||
| During analysis, completed profile tables and figures are streamed per sample | ||
| into the staging tree; source stacks are flushed immediately, and only compact texture records are | ||
| retained when one global texture-class fit is requested. | ||
| The output folder may sit below an input folder and is excluded from recursive | ||
| discovery. Input folders cannot be the output folder or sit below it, which | ||
| protects source images from plugin-owned stale-sample cleanup. |
These apply to single images and to every batch sample:
- Labels and raw channels must be greyscale (8-, 16- or 32-bit). RGB colour images are rejected; split them with Image > Color > Split Channels.
- Distances are measured in the label image's calibration. A raw channel whose calibration (pixel size or unit) differs from the label image is rejected; an uncalibrated raw channel is accepted. A 3D label image without calibration is measured with cubic voxels and a warning is written to the Log window.
- Labels in a 32-bit image must be whole numbers up to 16,777,216; larger values cannot be stored exactly and are rejected rather than silently merged.
- For a single-slice (2D) image the
MarginalZandPCThirdcurves have only one filled bin, the middle one, because the object has no depth. They are kept so that 2D and 3D tables have the same rows; ignore them for 2D data. - A one-voxel or one-line object is measured without error: curves it cannot
fill are blank, and shape measures that need spread in two directions
(
Elongation,Flatness) are blank. - With a single object, aggregate
SEMis blank, and texture and profile-shape classes put that object in class 1. - With GLCM on, a channel with no finite pixels stops the run with a message
naming the channel (and sample) unless a manual
quant_min/quant_maxpair is given. A constant channel is measured but flaggedGLCMReliable = false.
Map<String, ImagePlus> raw = new LinkedHashMap<>();
raw.put("DAPI", dapi);
raw.put("Marker", marker);
OipConfig config = new OipConfig();
config.doGlcm = true;
OipResult result = ObjectIntensityProfiling.run(
OipParameters.builder(labels)
.rawImages(raw)
.referenceChannel("DAPI")
.config(config)
.build());Folder batches use OipBatchParameters and OipBatchRunner. Capture group
1 in each filename regular expression is the sample key used to pair label
and raw files. Set the reference explicitly with
.referenceChannel("DAPI") when more than one raw channel is configured.
Use .quantizationRange("DAPI", new QuantizationRange(0, 65535)) to
override the automatic batch range.
Each raw profile bin is the arithmetic mean of finite raw values in that part of
the selected sampling region. Object-mask radial, marginal, shell, and
principal-axis coordinates are normalised to the object itself, so changing
box padding cannot change them. Whole-box mode instead normalises to the
padded box. Empty bins have no value: the CSVs leave the field blank and the
interactive tables show NaN. Neither is written as 0, because 0 is a
valid measurement for every one of these columns. Before curves are averaged
across objects, intensity_norm=minmax applies per-object min/max scaling,
mean divides by the per-object mean, and zscore subtracts that mean and
divides by the object's own standard deviation (an n, not n-1,
denominator). A constant object normalises to 0 under minmax and zscore,
because every voxel sits exactly at the object's centre. mean has no such
convention: when the object mean is zero, or negligible against the object's
own intensity range, the ratio is undefined and the curve is written as NaN
so the object is omitted from the aggregate rather than pulling it toward
zero. This is reached on any background-subtracted or mean-centred channel.
Shell intensity is reported as a full inner-to-outer curve. Shell overlap is the cosine overlap for the selected reference (A) and partner (B): (\sum AB / \sqrt{\sum A^2\sum B^2}), calculated separately in each shell. The same cosine definition is used for the whole-region overlap coefficient. Pearson correlation is mean-centred. Manders M1 is the non-negative reference intensity above the partner threshold divided by all non-negative reference intensity; M2 reverses the channels and uses the reference threshold.
Ring completeness is the fraction of angular bins reaching the
ring_threshold percentage of the curve maximum. Angular uniformity is one
minus the coefficient of variation of the same curve, clamped at zero; an
empty angular bin counts as zero signal rather than being skipped, so the two
agree on the same object.
The AxisNorm column carries each bin's position along its own profile axis:
0 to 1 for radial and shell curves, -1 to 1 for the marginal and principal-axis
curves, and degrees (0 to 360) for angular curves.
GLCMReliable is true only when the object's co-occurrence features came from
a full four-direction average with at least two occupied grey levels and a
defined correlation in every contributing slice. A thin object or slice that
can only supply one direction is measured but reported unreliable.
Aggregate curves are object-weighted. The plotted error is the standard
error of the mean (SEM), calculated from sample variance with (n-1) in the
variance denominator; missing bins are omitted independently. SEM is NaN
when only one object contributes to a bin.
GLCM features are two-dimensional and mask-restricted. Each of the four
directions gets its own co-occurrence matrix, and the five features are
computed per direction and then averaged, which is the standard Haralick
definition and matches CellProfiler's MeasureTexture. (Pooling all four
directions into a single matrix before computing would leave contrast and
homogeneity nearly unchanged but halve the angular second moment and double
the entropy, because those two are non-linear in the matrix.) For a 3D object
the per-slice results are then averaged across occupied Z slices having at
least 16 valid co-occurrence pairs; smaller slices are omitted as unreliable.
Gabor/wavelet class features use a mask-restricted maximum-intensity
projection (MIP), tightened to the mask extent before filtering; profile box
padding therefore cannot change texture features. The Gabor bank is fixed —
a 4-pixel carrier wavelength, a 2-pixel envelope and a 13-pixel kernel, the
same filter applied to every object — for the same reason one GLCM
quantisation range is used across a batch. Signal from other labels,
background, or missing (NaN) columns cannot
enter the projection or convolution. Invalid feature vectors are marked and
exported with blank feature values. Feature vectors from objects smaller than
the 13-pixel Gabor kernel are reported as unreliable and are excluded from
texture-class fitting, assignment, and class maps.
Before clustering, each of the eight features is standardised over the objects being fitted (per-channel, subtracting the mean and dividing by the standard deviation). Without this the four wavelet energies, which are in squared intensity units, are several orders of magnitude larger than the four Gabor responses and alone decide the clustering. The exported class distance is therefore in standardised feature units, not intensity units.
All eight texture features retain some dependence on object size, and the fixed Gabor bank reduces that dependence without removing it. Both filter families are evaluated with zero padding outside the object, so every mask pixel within half a kernel of the edge sees a truncated neighbourhood, and the feature is the mean over all mask pixels. Small objects are therefore mostly boundary. Measured on one identical period-4 grating at several object sizes, the spread in each feature is:
| Object size range | Aligned Gabor | Other three orientations | Wavelet energies |
|---|---|---|---|
| side 20 to 60 | 1.2x | 1.5-2.7x | 1.1-2.9x |
| side 13 to 200 | 1.4x | 2.2-5.2x | 1.1-11x |
The three off-axis Gabor responses are near zero for this grating, so they are dominated by that boundary term. Because clustering standardises every feature, all eight get equal say, so texture classes will partly track object size whenever sizes vary widely. Compare texture classes within a narrow size range, and treat a class that correlates with object size as an artefact until shown otherwise.
Zernike moments (zernike) describe how each channel's signal is arranged
around the object's centre. They are computed on the same mask-restricted
maximum-intensity projection as the texture classes, so a 3D object is
described by its projection (true 3D Zernike moments are planned for a later
version). The unit disk is centred on the mask centroid with radius equal to
the largest centroid-to-pixel distance plus half a pixel. For each order
(n = 0 \ldots) zernike_degree and repetition (m = n, n-2, \ldots \ge 0),
(Z_{nm} = \sum I , R_{nm}(\rho) , e^{-im\theta}) over the object's finite
pixels; Magnitude is (|Z_{nm}| / \sum I) and Phase is
(\operatorname{atan2}(\operatorname{Im} Z_{nm}, \operatorname{Re} Z_{nm})) in
radians. Magnitude is dimensionless, so it does not change when intensity is
scaled, and (0,0) is always 1. This differs from CellProfiler's
MeasureObjectIntensityDistribution, which scales x and y by the minimum
enclosing circle, divides the magnitude by the object's pixel count (so its
magnitudes scale with intensity) and reports phase as atan2(Re, Im); the
numbers are therefore not interchangeable. Moments are blank when the object's
total intensity is not positive, and ZernikeReliable is false when the disk
radius is under 5 pixels. Objects below minimum_texture_voxels are still
measured. On the square pixel grid even a perfect disk shows a small four-fold
term ((m = 4, 8), below 0.01 at a 30-pixel radius).
Profile-shape classes (profile_classes) group objects whose normalised curve
of one type (profile_class_type, radial by default) has a similar shape, for
example centre-bright versus rim-bright objects. Each partner channel is
clustered separately, on the curve exactly as written to
Per_Object_Profiles.csv (ValueNorm, so the choice of intensity_norm
matters), with the same seeded k-means as texture classes. In a folder batch
the classes are fitted once over every sample's objects, so class 2 means the
same shape in every sample. Class numbers follow the sorted order of the class
centres, not brightness or any biological ranking: read what a class means from
Aggregate/Profile_Class_Curves.csv or its figure, which overlays the class
means for each partner channel. ClassDistance is the Euclidean distance to
the class centre in normalised curve units. An object whose curve has an empty
bin (common for small objects with many radial_bins) cannot be compared and
gets a blank class; use fewer bins or the shell curve for small objects.
profile_k is reduced to the number of usable objects when there are fewer.
Angular and marginal curves are measured in image axes, so objects of the same
shape but different orientation fall into different classes; use them only
when orientation is part of the question.
Two further reading notes. GLCM quantisation spans the whole batch, so one very
bright image can push a dim object's voxels into a single grey level; the
resulting contrast 0, ASM 1, entropy 0 are arithmetically correct but carry no
texture information, and GLCMReliable is false in that case. And all
measurements read raw stored pixel values, ignoring any ImageJ density
calibration set through Image > Adjust > Calibrate...; this matters only for
signed 16-bit or explicitly calibrated images.
sh ./mvnw -B clean verify runs the unit tests, the golden-output digests
and a packaging check of the shaded jar.
A smoke test runs the packaged plugin inside a real Fiji. Point FIJI_HOME at
a disposable copy of Fiji, because the script replaces any
Object_Intensity_Profiling jar in its plugins/ folder:
FIJI_HOME=/path/to/Fiji-copy bash src/test/fiji/run-smoke.shIt builds the jar, runs src/test/fiji/oip-smoke.ijm headless (menu
registration, 2D and 3D single-image runs, a two-sample batch), checks that a
bad option stops the macro with a one-line message and no stack trace, and
prints SMOKE OK. On Windows the Fiji launcher's console output cannot be
captured, so the script asks Fiji's Jaunch configurator for the Java command
and starts Fiji's bundled Java directly. To compare the Fiji run's 2D tables
with the same run under JUnit, keep the work folder (SMOKE_DIR=...) and run
sh ./mvnw -B -q test -Dtest=SmokeParityTest -Doip.smoke.dir=<SMOKE_DIR>.
Per-object profiles and independent (raw channel, object) texture measurements use deterministic
indexed workers. Texture-class fitting remains a serial barrier after all feature vectors are ready.
The automatic limit is eight workers; set the JVM system property oip.parallelism to a positive
integer to override it, or to 1 for the serial reference path.
Each run fetches every slice of the label image and of each raw image once, before the workers start, and the workers share those slices read-only. A virtual stack is therefore read from disk once per run and held in memory for that run; the Log names each virtual stack read this way and its size. Open a virtual stack normally, or use a smaller crop, if that copy will not fit in memory.
Synthetic benchmark (oip.bench.OipBenchmark in the test sources; two float raw channels,
1,024 spherical objects, JDK 21, 16 logical processors, median of three timed runs; the
2048 x 2048 "before" figures are single runs). "Default" uses the automatic worker count (eight).
| Image and measurement | Before 0.3.0, serial | 0.3.0, serial | Before 0.3.0, default | 0.3.0, default |
|---|---|---|---|---|
| 512 x 512 x 24, profiles | 12.5 s | 1.1 s | 2.7 s | 0.33 s |
| 512 x 512 x 24, GLCM | 8.4 s | 2.0 s | 1.7 s | 0.49 s |
| 512 x 512 x 24, texture classes | 6.7 s | 2.0 s | 1.5 s | 0.56 s |
| 2048 x 2048 x 10, profiles | 157 s | 1.9 s | 24.7 s | 0.83 s |
Earlier versions asked ImageJ for each slice again for every object. When the displayed slice of an image is blank, as the first slice of most 3D label stacks is, ImageJ rescans the whole slice on every such request, so the cost grew with slice size times object count. Outputs are unchanged.
To rerun the benchmark, build with sh ./mvnw -DskipTests package, then run it against the
plugin jar and the ImageJ jar from your Maven repository (use : instead of ; on macOS and
Linux). The arguments are small or large and a comma list of profiles, glcm, classes:
java -cp "target/Object_Intensity_Profiling-<version>.jar;target/test-classes;<path to ij-1.54p.jar>" oip.bench.OipBenchmark small profiles,glcm,classesIf you use Object Intensity Profiling, please cite it (see also CITATION.cff):
Malcolm, J. (2026). Object Intensity Profiling (v0.3.1) [Software]. GitHub. https://github.com/Jay2owe/ObjectIntensityProfiling
Developed by Jamie Malcolm in the Brancaccio Lab at the UK Dementia Research Institute, Imperial College London.
This work was supported by the UK Dementia Research Institute, which receives its core funding from the UK Medical Research Council, the Alzheimer's Society, and Alzheimer's Research UK.
Built on the Fiji / ImageJ ecosystem; we thank the SciJava community for the platform.
BSD 3-Clause. See LICENSE; attribution is in NOTICE. Both ship inside the
jar under META-INF/.
