Relative-Intensity Pattern Registration (RIPR)
This is a native Python package for the same registration operation as the Java Fiji/ImageJ plugin in this repository. It separates global intensity gain from movement, supports the log-ratio and area- correlation pair estimators, reconciles multiple frame gaps, repairs unsupported transforms, and applies one timepoint transform to every channel and Z plane.
The numerical engine is Python/NumPy/SciPy. It does not launch ImageJ and does not require Java.
Its distribution name, import package and terminal command are all ripr.
Install
From this folder:
python -m pip install -e .
For development and tests:
python -m pip install -e ".[test]"
pytest
Register a NumPy array
import tifffile
from ripr import LogRatioParameters, register
stack = tifffile.imread("recording.tif") # shape T, Y, X
parameters = LogRatioParameters.recommended(
image_type="phase_contrast",
motion_type="subpixel_random_walk",
)
result = register(stack, parameters, axes="TYX")
tifffile.imwrite("recording_registered.tif", result.corrected)
print([(t.dx, t.dy, t.theta) for t in result.transforms]) # theta is radians
print(result.registration.log2_gain) # bleaching/lamp-drift trace
print(result.median_residual_before, result.median_residual_after)
Use ripr.rank_channels(array, axes="TCZYX") to rank estimation channels by localisability before
a run. Values below ripr.WARN_BELOW carry the same poor-localisability warning threshold as the
ImageJ plugin.
The input is never modified. For hyperstacks, pass axes explicitly, for example TCZYX. channel,
slice, and reference_frame in LogRatioParameters are one-based like ImageJ; slice=0 maximum-
projects Z for movement estimation. The estimated transform is applied unchanged to every channel and
Z plane.
Run the estimation in Java, at Java speed
The registration in this package and the registration in the Fiji plugin are the same operation, and on a preset recipe they produce the same transforms bit for bit. They do not take the same amount of time. Java aligns frame pairs across a thread pool, which is the one place this problem parallelises well, and the NumPy engine here runs them one after another.
If a Java runtime and the plugin jar are both present, hand the estimation over:
result = register(stack, parameters, axes="TYX", backend="java")
Measured on one 40-frame 448x768 recording, 16 cores, identical settings and identical output:
| Engine | Time |
|---|---|
backend="java" |
16.6 s |
backend="python" |
over 900 s |
backend takes:
"python"— the NumPy engine, the default, never leaves the process"java"— require the plugin engine, and raise if it cannot run"auto"— use the plugin engine when it is available, fall back quietly when it is not
The default stays "python" so that installing this package beside a JDK cannot change what an
existing call returns. To turn the fast path on for a whole pipeline without editing its call sites,
set RIPR_BACKEND=auto in the environment.
Only transforms cross the process boundary; warping happens here either way, so the choice changes how long a run takes and not what it gives back. Two consequences worth knowing:
result.registration.pairsis empty under the Java backend. Per-pair fits are not carried across, because moving them costs more than a caller asking for a fast path wants to spend. Everything reported per frame is present and is the Java engine's own value.- The Java runner rebuilds the recipe from the image type, motion type and selection mode you name.
That is exact for a preset recipe and wrong for a customised one, so a recipe that differs from its
preset in any other field stays on the Python engine.
ripr.registration.java_incompatibilities()lists what is blocking it;backend="java"raises rather than silently running something else. SelectionMode.LONGITUDINAL_ACCURACYis not covered by the fast path and always runs here.
The backend finds its pieces from the environment: RIPR_JAVA or JAVA_HOME or java on PATH
for the runtime, and RIPR_JAR or a jars/ directory beside the package or RIPR_FIJI for the
plugin. ripr.java_backend.available() reports whether it can run at all.
Register a TIFF or folder
from ripr import register_file, register_batch
register_file("recording.ome.tif", "recording_registered.tif", parameters)
register_batch("input_folder", "output_folder", parameters, recursive=True)
Or from a shell:
ripr recording.tif recording_registered.tif `
--image-type phase_contrast --motion-type subpixel_random_walk `
--fit-rotation --max-rotation-degrees 10
ripr remounted_recording.tif remounted_registered.tif `
--rotation-mode known_events --rotation-events 25,51 `
--rotation-event-window 3 --max-rotation-degrees 10
ripr input_folder output_folder --recursive
Folder batches create log_ratio_batch_report.csv, skip existing outputs unless --overwrite is set,
and continue after a damaged or incompatible input. The existing report columns are followed by the
resolved rotation mode, one-based event list, window and compact event diagnostics.
Java-to-Python interface map
| Java plugin/API | Python package |
|---|---|
RelativeIntensityPatternRegistration.register(ImagePlus, ...) |
ripr.register(ndarray, ..., axes=...) |
RelativeIntensityPatternRegistration.estimate(...) |
ripr.estimate(...) |
RelativeIntensityPatternParameters |
ripr.LogRatioParameters |
RelativeIntensityPatternRecommendations.forTypes(...) |
ripr.recommendation(...) |
StackWarper.apply(...) |
ripr.apply_transforms(...) |
| batch plugin | ripr.register_batch(...) |
| TIFF input/output | ripr.register_file(...) |
Set fit_rotation=True and max_rotation_degrees=<bound> on LogRatioParameters to estimate bounded
in-plane rotation as well as translation. The public bound is in degrees; returned Transform.theta
values are radians. Both log-ratio and area-correlation estimators support the rigid search. Automatic is
a fixed declared image-and-motion rule and never inspects the recording to choose a recipe. Dense and
low-light fluorescence use single_channel_emission_max_accuracy_r04_a208: dense fluorescence
uses median-filtered previous-image Enhanced Correlation Coefficient, while sparse/low-light
fluorescence or bioluminescence uses the tuned log-ratio preset. Other image types retain
recording_adaptive_selector_v1_user_approved_fixed_policy_v1.
For long recordings with slow drift, gentle shake, isolated stage movements and major light changes, choose the separate whole-recording route:
from ripr import ImageType, LogRatioParameters, SelectionMode
parameters = LogRatioParameters(
image_type=ImageType.SPARSE_LOW_LIGHT_FLUORESCENCE,
selection_mode=SelectionMode.LONGITUDINAL_ACCURACY,
channel=1,
)
This route uses bright/dim same-channel references for fluorescence or bioluminescence and edge/dark landmarks for phase contrast or brightfield/DIC. It suppresses returning pulse-linked excursions while retaining persistent and near-dark final jumps. It never reads another channel. Use Automatic instead for repeated oscillation or continuous rotation.
For recordings that rotate only when they are removed and replaced, use the experimental event mode:
from ripr import LogRatioParameters, RotationMode
parameters = LogRatioParameters.manual(
rotation_mode=RotationMode.KNOWN_EVENTS,
rotation_event_frames=(25, 51), # one-based first frames after remounting
rotation_event_window=3,
max_rotation_degrees=10,
)
Each boundary uses all available before/after cross-pairs in the window and needs at least three usable
rigid fits. One robust angular jump is held exactly until the next event while translation remains free.
The final composed transforms are applied to the original pixels once. Event diagnostics are available
as result.registration.event_rotations; they include the event frame, incremental and cumulative angle,
candidate/usable/inlier counts, circular spread, contributing ranges and status. Large disagreement is a
warning; insufficient support stops the run. This mode uses the log-ratio estimator, does not support a
rolling reference, and remains opt-in pending validation on independent real remount recordings.
Interpolation.NONE remains the default: pure translations are rounded to whole pixels and applied
through a bit-exact block copy. A non-zero rotation cannot use that path, so NONE uses nearest-neighbour
sampling; bilinear and Catmull-Rom bicubic interpolation are opt-in for smoother intensity images.
Interpolation.FOURIER uses padded Fourier shifts for sharp, band-limited interpolation and represents
rotation as three Fourier shears. It can ring near hard edges.
Cropping defaults to the field containing real pixels in every registered frame.
This is a standalone Python package, separate from the Java plugin. It has no Swing dialogs or ImageJ macro recorder; its settings are exposed through the Python API and command-line interface. The Java plugin and Python package can continue to be used independently.
Release files for ripr 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ripr-0.2.0.tar.gz | 98.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ripr-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 181.9 kB
Release files / ripr-0.2.0.tar.gz
| Download URL | ripr-0.2.0.tar.gz |
|---|---|
| Size | 98.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ad8101f0f8ae65748d8bb1c83130180664356359e7bdacf3924b82296ef783c5
|
|
BLAKE2b-256 checksum How to use checksums |
06a4233da50e54d2e6c7e5687e3f54a03ad82aecbc10467a70c3629d2a3e3917
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|
Release files / ripr-0.2.0-py3-none-any.whl
| Download URL | ripr-0.2.0-py3-none-any.whl |
|---|---|
| Size | 83.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3cf2c1d21ac048080dd9d9a5b983d290c8cb60eff8b4eca4bdce20f9d3f408e7
|
|
BLAKE2b-256 checksum How to use checksums |
e972b4020163f490b92f66d53fd108fc84a25146a02069b0e1338a8dbaae68a2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|