Skip to main content

Image registration tool (python implementation of the ImageJ/FIJI Plugin TurboReg/StackReg)

Project description

pyStackReg

Build & Test Documentation Status PyPI Package latest release Supported Python Versions Downloads

Summary

Python/C++ port of the ImageJ extension TurboReg/StackReg written by Philippe Thevenaz/EPFL.

A python extension for the automatic alignment of a source image or a stack (movie) to a target image/reference frame.

Description

pyStackReg is used to align (register) one or more images to a common reference image, as is required usually in time-resolved fluorescence or wide-field microscopy. It is directly ported from the source code of the ImageJ plugin TurboReg and provides additionally the functionality of the ImageJ plugin StackReg, both of which were written by Philippe Thevenaz/EPFL (available at http://bigwww.epfl.ch/thevenaz/turboreg/).

pyStackReg provides the following five types of distortion:

  • translation

  • rigid body (translation + rotation)

  • scaled rotation (translation + rotation + scaling)

  • affine (translation + rotation + scaling + shearing)

  • bilinear (non-linear transformation; does not preserve straight lines)

pyStackReg supports the full functionality of StackReg plus some additional options, e.g., using different reference images and having access to the actual transformation matrices (please see the examples below). Note that pyStackReg uses the high quality (i.e. high accuracy) mode of TurboReg that uses cubic spline interpolation for transformation.

Please note: The bilinear transformation cannot be propagated, as a combination of bilinear transformations does not generally result in a bilinear transformation. Therefore, stack registration/transform functions won’t work with bilinear transformation when using “previous” image as reference image. You can either use another reference (“first” or “mean” for first or mean image, respectively), or try to register/transform each image of the stack separately to its respective previous image (and use the already transformed previous image as reference for the next image).

Installation

The package is available on conda forge and on PyPi.

  • Install using conda

conda install pystackreg -c conda-forge
  • Install using pip

pip install pystackreg

Documentation

The documentation can be found on readthedocs:

https://pystackreg.readthedocs.io/

Tutorial

Usage

The following example opens two different files and registers them using all different possible transformations

from pystackreg import StackReg
from skimage import io

#load reference and "moved" image
ref = io.imread('some_original_image.tif')
mov = io.imread('some_changed_image.tif')

#Translational transformation
sr = StackReg(StackReg.TRANSLATION)
out_tra = sr.register_transform(ref, mov)

#Rigid Body transformation
sr = StackReg(StackReg.RIGID_BODY)
out_rot = sr.register_transform(ref, mov)

#Scaled Rotation transformation
sr = StackReg(StackReg.SCALED_ROTATION)
out_sca = sr.register_transform(ref, mov)

#Affine transformation
sr = StackReg(StackReg.AFFINE)
out_aff = sr.register_transform(ref, mov)

#Bilinear transformation
sr = StackReg(StackReg.BILINEAR)
out_bil = sr.register_transform(ref, mov)

The next example shows how to separate registration from transformation (e.g., to register in one color channel and then use that information to transform another color channel):

from pystackreg import StackReg
from skimage import io

img0 = io.imread('some_multiframe_image.tif')
img1 = io.imread('another_multiframe_image.tif')
# img0.shape: frames x width x height (3D)

sr = StackReg(StackReg.RIGID_BODY)

# register 2nd image to 1st
sr.register(img0[0, :, :], img0[1,:,:])

# use the transformation from the above registration to register another frame
out = sr.transform(img1[1,:,:])

The next examples shows how to register and transform a whole stack:

from pystackreg import StackReg
from skimage import io

img0 = io.imread('some_multiframe_image.tif') # 3 dimensions : frames x width x height

sr = StackReg(StackReg.RIGID_BODY)

# register each frame to the previous (already registered) one
# this is what the original StackReg ImageJ plugin uses
out_previous = sr.register_transform_stack(img0, reference='previous')

# register to first image
out_first = sr.register_transform_stack(img0, reference='first')

# register to mean image
out_mean = sr.register_transform_stack(img0, reference='mean')

# register to mean of first 10 images
out_first10 = sr.register_transform_stack(img0, reference='first', n_frames=10)

# calculate a moving average of 10 images, then register the moving average to the mean of
# the first 10 images and transform the original image (not the moving average)
out_moving10 = sr.register_transform_stack(img0, reference='first', n_frames=10, moving_average = 10)

The next example shows how to separate registration from transformation for a stack (e.g., to register in one color channel and then use that information to transform another color channel):

from pystackreg import StackReg
from skimage import io

img0 = io.imread('some_multiframe_image.tif') # 3 dimensions : frames x width x height
img1 = io.imread('another_multiframe_image.tif') # same shape as img0

# both stacks must have the same shape
assert img0.shape == img1.shape

sr = StackReg(StackReg.RIGID_BODY)

# register each frame to the previous (already registered) one
# this is what the original StackReg ImageJ plugin uses
tmats = sr.register_stack(img0, reference='previous')
out = sr.transform_stack(img1)

# tmats contains the transformation matrices -> they can be saved
# and loaded at another time
import numpy as np
np.save('transformation_matrices.npy', tmats)

tmats_loaded = np.load('transformation_matrices.npy')

# make sure you use the correct transformation here!
sr = StackReg(StackReg.RIGID_BODY)

# transform stack using the tmats loaded from file
sr.transform_stack(img1, tmats=tmats_loaded)

# with the transformation matrices at hand you can also
# use the transformation algorithms from other packages:
from skimage import transform as tf

out = np.zeros(img0.shape).astype(np.float)

for i in range(tmats.shape[0]):
    out[i, :, :] = tf.warp(img1[i, :, :], tmats[i, :, :], order=3)

Author information

This is a port of the original Java code by Philippe Thevenaz to C++ with a Python wrapper around it. All credit goes to the original author:

/*====================================================================
| Philippe Thevenaz
| EPFL/STI/IMT/LIB/BM.4.137
| Station 17
| CH-1015 Lausanne VD
| Switzerland
|
| phone (CET): +41(21)693.51.61
| fax: +41(21)693.37.01
| RFC-822: philippe.thevenaz@epfl.ch
| X-400: /C=ch/A=400net/P=switch/O=epfl/S=thevenaz/G=philippe/
| URL: http://bigwww.epfl.ch/
\===================================================================*/

/*====================================================================
| This work is based on the following paper:
|
| P. Thevenaz, U.E. Ruttimann, M. Unser
| A Pyramid Approach to Subpixel Registration Based on Intensity
| IEEE Transactions on Image Processing
| vol. 7, no. 1, pp. 27-41, January 1998.
|
| This paper is available on-line at
| http://bigwww.epfl.ch/publications/thevenaz9801.html
|
| Other relevant on-line publications are available at
| http://bigwww.epfl.ch/publications/
\===================================================================*/

License

You are free to use this software for commercial and non-commercial
purposes. However, we expect you to include a citation or acknowledgement
whenever you present or publish research results that are based
on this software. You are free to modify this software or derive
works from it, but you are only allowed to distribute it under the
same terms as this license specifies. Additionally, you must include
a reference to the research paper above in all software and works
derived from this software.

Changelog

0.2.7

fixed

  • Axis argument not used for method “mean” in register_stack() (PR #26)

0.2.6

added

  • exposing simple_slice and running_mean functions in util package

  • added conversion function to any integer dtype

0.2.5

fixed

  • Compilation in environment without numpy

0.2.3

added

  • Added example data and tutorial notebook

  • Added unit tests

  • Additional documentation

  • Detection of time series axis in stacks - will raise a warning if supplied axis in stack registration does not correspond to the detected axis

changed

  • progress_callback function now gets called with the iteration number, not iteration index (iteration number = iteration index + 1)

fixed

  • Fixed exception when using a different axis than 0 for registering stacks

0.2.2

changed

  • License changed to allow distribution on python package repositories

0.2.1

added

  • progress callback function can be supplied to register_stack() and register_transform_stack() functions via the progress_callback that is then called after every iteration (i.e. after each image registration)

changed

  • progress bar output not shown by default, has to be enabled by using the verbose=True parameter in the register_stack() and register_transform_stack() functions

0.2.0

added

  • bilinear transformation

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pystackreg-0.2.7.tar.gz (3.7 MB view hashes)

Uploaded Source

Built Distributions

pystackreg-0.2.7-cp311-cp311-win_amd64.whl (62.4 kB view hashes)

Uploaded CPython 3.11 Windows x86-64

pystackreg-0.2.7-cp311-cp311-win32.whl (54.3 kB view hashes)

Uploaded CPython 3.11 Windows x86

pystackreg-0.2.7-cp311-cp311-musllinux_1_1_x86_64.whl (1.3 MB view hashes)

Uploaded CPython 3.11 musllinux: musl 1.1+ x86-64

pystackreg-0.2.7-cp311-cp311-musllinux_1_1_i686.whl (1.4 MB view hashes)

Uploaded CPython 3.11 musllinux: musl 1.1+ i686

pystackreg-0.2.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (842.4 kB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ x86-64

pystackreg-0.2.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (824.3 kB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ i686 manylinux: glibc 2.5+ i686

pystackreg-0.2.7-cp311-cp311-macosx_10_9_x86_64.whl (93.6 kB view hashes)

Uploaded CPython 3.11 macOS 10.9+ x86-64

pystackreg-0.2.7-cp310-cp310-win_amd64.whl (62.4 kB view hashes)

Uploaded CPython 3.10 Windows x86-64

pystackreg-0.2.7-cp310-cp310-win32.whl (54.3 kB view hashes)

Uploaded CPython 3.10 Windows x86

pystackreg-0.2.7-cp310-cp310-musllinux_1_1_x86_64.whl (1.3 MB view hashes)

Uploaded CPython 3.10 musllinux: musl 1.1+ x86-64

pystackreg-0.2.7-cp310-cp310-musllinux_1_1_i686.whl (1.4 MB view hashes)

Uploaded CPython 3.10 musllinux: musl 1.1+ i686

pystackreg-0.2.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (842.3 kB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ x86-64

pystackreg-0.2.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (824.3 kB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ i686 manylinux: glibc 2.5+ i686

pystackreg-0.2.7-cp310-cp310-macosx_10_9_x86_64.whl (93.6 kB view hashes)

Uploaded CPython 3.10 macOS 10.9+ x86-64

pystackreg-0.2.7-cp39-cp39-win_amd64.whl (62.4 kB view hashes)

Uploaded CPython 3.9 Windows x86-64

pystackreg-0.2.7-cp39-cp39-win32.whl (54.3 kB view hashes)

Uploaded CPython 3.9 Windows x86

pystackreg-0.2.7-cp39-cp39-musllinux_1_1_x86_64.whl (1.3 MB view hashes)

Uploaded CPython 3.9 musllinux: musl 1.1+ x86-64

pystackreg-0.2.7-cp39-cp39-musllinux_1_1_i686.whl (1.4 MB view hashes)

Uploaded CPython 3.9 musllinux: musl 1.1+ i686

pystackreg-0.2.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (842.2 kB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ x86-64

pystackreg-0.2.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (824.1 kB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ i686 manylinux: glibc 2.5+ i686

pystackreg-0.2.7-cp39-cp39-macosx_10_9_x86_64.whl (93.6 kB view hashes)

Uploaded CPython 3.9 macOS 10.9+ x86-64

pystackreg-0.2.7-cp38-cp38-win_amd64.whl (62.4 kB view hashes)

Uploaded CPython 3.8 Windows x86-64

pystackreg-0.2.7-cp38-cp38-win32.whl (54.3 kB view hashes)

Uploaded CPython 3.8 Windows x86

pystackreg-0.2.7-cp38-cp38-musllinux_1_1_x86_64.whl (1.3 MB view hashes)

Uploaded CPython 3.8 musllinux: musl 1.1+ x86-64

pystackreg-0.2.7-cp38-cp38-musllinux_1_1_i686.whl (1.4 MB view hashes)

Uploaded CPython 3.8 musllinux: musl 1.1+ i686

pystackreg-0.2.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (842.8 kB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.17+ x86-64

pystackreg-0.2.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (824.7 kB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.17+ i686 manylinux: glibc 2.5+ i686

pystackreg-0.2.7-cp38-cp38-macosx_10_9_x86_64.whl (93.6 kB view hashes)

Uploaded CPython 3.8 macOS 10.9+ x86-64

pystackreg-0.2.7-cp37-cp37m-win_amd64.whl (62.3 kB view hashes)

Uploaded CPython 3.7m Windows x86-64

pystackreg-0.2.7-cp37-cp37m-win32.whl (54.2 kB view hashes)

Uploaded CPython 3.7m Windows x86

pystackreg-0.2.7-cp37-cp37m-musllinux_1_1_x86_64.whl (1.3 MB view hashes)

Uploaded CPython 3.7m musllinux: musl 1.1+ x86-64

pystackreg-0.2.7-cp37-cp37m-musllinux_1_1_i686.whl (1.4 MB view hashes)

Uploaded CPython 3.7m musllinux: musl 1.1+ i686

pystackreg-0.2.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (841.5 kB view hashes)

Uploaded CPython 3.7m manylinux: glibc 2.17+ x86-64

pystackreg-0.2.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (823.6 kB view hashes)

Uploaded CPython 3.7m manylinux: glibc 2.17+ i686 manylinux: glibc 2.5+ i686

pystackreg-0.2.7-cp37-cp37m-macosx_10_9_x86_64.whl (93.6 kB view hashes)

Uploaded CPython 3.7m macOS 10.9+ x86-64

pystackreg-0.2.7-cp36-cp36m-win_amd64.whl (64.2 kB view hashes)

Uploaded CPython 3.6m Windows x86-64

pystackreg-0.2.7-cp36-cp36m-win32.whl (56.0 kB view hashes)

Uploaded CPython 3.6m Windows x86

pystackreg-0.2.7-cp36-cp36m-musllinux_1_1_x86_64.whl (1.3 MB view hashes)

Uploaded CPython 3.6m musllinux: musl 1.1+ x86-64

pystackreg-0.2.7-cp36-cp36m-musllinux_1_1_i686.whl (1.4 MB view hashes)

Uploaded CPython 3.6m musllinux: musl 1.1+ i686

pystackreg-0.2.7-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (843.1 kB view hashes)

Uploaded CPython 3.6m manylinux: glibc 2.17+ x86-64

pystackreg-0.2.7-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (826.1 kB view hashes)

Uploaded CPython 3.6m manylinux: glibc 2.17+ i686 manylinux: glibc 2.5+ i686

pystackreg-0.2.7-cp36-cp36m-macosx_10_9_x86_64.whl (95.1 kB view hashes)

Uploaded CPython 3.6m macOS 10.9+ x86-64

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page