Skip to main content

Image registration models with extendable interfaces.

Project description

imgreg

pipeline status coverage report

An image registration library for python including a simple interface for building new models. Currently two image registration models for linear transformations based on scikit have been implemented as part of a toolchain in the context of particle image velocimetry (PIV). Tested for Python 3.7 to Python 3.9.

Installation

pip install imgreg

or clone the repository, and run:

python setup.py install

Examples

The following example give a short introduction into the available models. For further reading the directory doc/tutorial provides a good starting point. The full documentation can be generated using sphinx.

Recover the rotation and translation between two images

First import the model (here based on the logpolar and fourier transformation) and load the image files into the model:

import numpy as np
import imgreg.data as data
from imgreg.models.logpolar import LogPolarSolver

ref_img = np.array(data.ref_img())
mod_img = np.array(data.mod_img())
lps = LogPolarSolver(ref_img, mod_img)

The images can be displayed with:

lps.display([lps.REF_IMG, lps.MOD_IMG])

reference vs modified image

To access the recovered rotation angle and lower error bound in degrees use:

lps.RECOVERED_ROTATION.value
# array([-13.06730769,   0.11259774])

The recovered x,y translation and lower error bound given in number of pixels is accessed with:

lps.RECOVERED_TRANSLATION.value
# array([-17.98318062,  31.037803  ,   0.42407651])

The recovered scaling factor is available with:

lps.RECOVERED_SCALE.value
# array([1.        , 1.00187429])

A comparision between the recovered and the reference image can be displayed with:

lps.display([lps.RECOVERED_ROT_SCALE_TR_IMG, lps.REF_IMG])

recovered vs reference image

Batch image processing

First import the required modules (here we use less general domain specific RadonSolver model, if not suitable for your application, repace with the LogPolarSolver as in the previous example):

import os
import pandas as pd

import matplotlib.pyplot as plt
import numpy as np
from PIL import Image

from imgreg.models.radon import RadonSolver
from imgreg.util.helpers import image_save_back_tf, rot_tr_gen, solver_gen
from imgreg.util.io import DirectoryView

Define the location to your reference image according to your usecase by replacing <path/to/reference/image.jpg>, then replace the location of your source <src> and destination <dest> paths. Adjust the file_pattern and step variables to your needs, the latter can be used to skip images for faster computation.

image_path_ref = "<path/to/reference/image.jpg>"
image_path_src = "<src>"
image_path_dest = "<dest>"
file_pattern = "*.jpg"
step = 10

Create a directory view from which the solver generates its input:

d_view = DirectoryView(image_path_src, file_pattern=file_pattern)
fnames = [file for i, file in enumerate(sorted(d_view.files)) if not i % step]

Load the reference image:

ref_img = np.array(Image.open(image_path_ref))

Initialize and configure a suitable solver:

ras = RadonSolver(ref_img=ref_img)
ras.UPSAMPLING.value = 20

Generate an array containing the recovered translation and rotation parameters for the given images:

radg = solver_gen(d_view, ras, step)
rad_rot_tr_arr = np.array(list(rot_tr_gen(radg)))

Display the relative norm NormRel_L2 over the image series as an indicator for the goodness of the recovered values:

plt.plot(rad_rot_tr_arr[:, -1])
plt.xlabel("# image")
plt.ylabel("NormRel_L2")
plt.show()

plot of the relative difference L2 norm

Store recovered values to .csv

df_out = pd.DataFrame(
    rad_rot_tr_arr,
    index=fnames,
    columns=[
        "tr_x",
        "tr_y",
        "tr_err",
        "rot",
        "rot_err",
        "NormRel_L2",
    ],
)
df_out.to_csv(f"radon-{step}.csv")
df_out
tr_x tr_y tr_err rot rot_err NormRel_L2
test00001.jpg -26.4509 47.3258 0.405569 -20.5556 0.282843 0.41641
test00011.jpg -26.3339 47.1561 0.405386 -20.5556 0.282843 0.415555
test00021.jpg -26.2344 47.0332 0.405536 -20.5556 0.282843 0.415513
test00031.jpg -22.8071 42.6237 0.385188 -18.4444 0.282843 0.396469
test00041.jpg -18.4961 36.5684 0.366198 -16 0.282843 0.379106
test00051.jpg -14.7056 30.9144 0.343007 -13.5556 0.282843 0.35666
test00061.jpg -11.768 25.8513 0.316403 -11.2469 0.282843 0.329185
test00071.jpg -8.66827 20.3634 0.288842 -8.80247 0.282843 0.300223
test00081.jpg -6.02938 15.0685 0.258316 -6.44444 0.282843 0.267387
test00091.jpg -3.50923 9.32793 0.220809 -4 0.282843 0.227255
test00101.jpg -1.19596 3.51883 0.172761 -1.55556 0.282843 0.175223
test00111.jpg 0.575633 -1.85773 0.129057 0.753086 0.282843 0.126313
test00121.jpg 2.41049 -7.94683 0.167134 3.19753 0.282843 0.16156
test00131.jpg 3.81275 -13.2214 0.200897 5.44444 0.282843 0.198397
test00141.jpg 5.16611 -19.4011 0.234146 7.95062 0.282843 0.240847
test00151.jpg 6.11063 -24.7732 0.264576 10.1975 0.282843 0.289057
test00161.jpg 6.97132 -31.2601 0.29121 12.7531 0.282843 0.335311
test00171.jpg 7.47346 -36.6325 0.317422 15 0.282843 0.387218
test00181.jpg 7.68796 -41.7207 0.34348 17 0.282843 0.426283
test00191.jpg 7.70654 -41.831 0.345591 17 0.282843 0.42826
test00201.jpg 7.69192 -41.8788 0.349477 17 0.282843 0.4287
test00211.jpg 7.65427 -39.2652 0.338767 15.9506 0.282843 0.405673
test00221.jpg 7.37055 -33.822 0.325869 13.7531 0.282843 0.370918
test00231.jpg 7.39534 -33.931 0.327034 13.7531 0.282843 0.372402
test00241.jpg 7.38345 -33.9795 0.33014 13.7531 0.282843 0.375312
test00251.jpg 7.11119 -31.5481 0.321188 12.7531 0.282843 0.357117

Load the recovered values from .csv

df_in = pd.read_csv(f"radon-{step}.csv", index_col=0, sep=",")
rad_rot_tr_arr = df_in.to_numpy()
fnames = df_in.index

If desired an offset can be applied to a column of the data for plotting:

rad_rot_tr_arr[:, 3] -= 15
plt.plot(rad_rot_tr_arr[:, 3])
plt.xlabel("# image")
plt.ylabel("angle")
plt.show()

plot of the angles with an offset

Save the reconstructed images

Finally the table of reconstructed parameters can be used to save the backtransformed images.

image_save_back_tf(rad_rot_tr_arr, fnames, image_path_src, image_path_dest)

A word on the models

The implemented models differ in some of the internal parameters. As the construction of a model also defines the dependency tree of its parameters, we can display a representation of the dependency tree as follows for every model (shown for the RadonSolver):

from imgreg.models.radon import RadonSolver
from imgreg.util.graph import dot_args_box_img_func

ras=RadonSolver()
ras.dot_graph(dot_args_box_img_func)

A dependency graph representation of the RadonSolver

Tutorials

Further interactive examples are available as jupyter-notebooks in doc/tutorial.

Documentation

The API documentation can be generated using Sphinx with numpydoc formatting. To build, run:

sphinx-build -b html doc/ doc/_build/html

Testing

To run all tests and to generate a coverage report run:

pytest --cov=imgreg/ tests/
coverage html

To test the examples in the documentation run:

pytest --doctest-modules imgreg/

License

This software is published under the GPLv3 license.

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

imgreg-1.0.1.tar.gz (42.3 kB view hashes)

Uploaded Source

Built Distribution

imgreg-1.0.1-py3-none-any.whl (357.2 kB view hashes)

Uploaded Python 3

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