Skip to content

Repository files navigation

imgreg

pkgversionversionsupportrepositorypipeline statuscoverage reportlicenseCode style: blackdocsDownloads

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

imgreg is directly available from pypi:

pip install imgreg

alternatively clone the repository, and install with:

git clone https://gitlab.com/DigonIO/imgreg.git
cd imgreg
python setup.py install

Examples

The following examples give a short introduction into the available models. For further reading the directory doc/tutorial provides a good starting point. The full documentation is available online.

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:

importnumpyasnpimportimgreg.dataasdatafromimgreg.models.logpolarimportLogPolarSolverref_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 the less general domain specific RadonSolver model, if not suitable for your application, repace with the LogPolarSolver as in the previous example):

importosimportpandasaspdimportmatplotlib.pyplotaspltimportnumpyasnpfromPILimportImagefromimgreg.models.radonimportRadonSolverfromimgreg.util.helpersimportimage_save_back_tf, rot_tr_gen, solver_genfromimgreg.util.ioimportDirectoryView

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= [filefori, fileinenumerate(sorted(d_view.files)) ifnoti%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_xtr_ytr_errrotrot_errNormRel_L2
test00001.jpg-26.450947.32580.405569-20.55560.2828430.41641
test00011.jpg-26.333947.15610.405386-20.55560.2828430.415555
test00021.jpg-26.234447.03320.405536-20.55560.2828430.415513
test00031.jpg-22.807142.62370.385188-18.44440.2828430.396469
test00041.jpg-18.496136.56840.366198-160.2828430.379106
test00051.jpg-14.705630.91440.343007-13.55560.2828430.35666
test00061.jpg-11.76825.85130.316403-11.24690.2828430.329185
test00071.jpg-8.6682720.36340.288842-8.802470.2828430.300223
test00081.jpg-6.0293815.06850.258316-6.444440.2828430.267387
test00091.jpg-3.509239.327930.220809-40.2828430.227255
test00101.jpg-1.195963.518830.172761-1.555560.2828430.175223
test00111.jpg0.575633-1.857730.1290570.7530860.2828430.126313
test00121.jpg2.41049-7.946830.1671343.197530.2828430.16156
test00131.jpg3.81275-13.22140.2008975.444440.2828430.198397
test00141.jpg5.16611-19.40110.2341467.950620.2828430.240847
test00151.jpg6.11063-24.77320.26457610.19750.2828430.289057
test00161.jpg6.97132-31.26010.2912112.75310.2828430.335311
test00171.jpg7.47346-36.63250.317422150.2828430.387218
test00181.jpg7.68796-41.72070.34348170.2828430.426283
test00191.jpg7.70654-41.8310.345591170.2828430.42826
test00201.jpg7.69192-41.87880.349477170.2828430.4287
test00211.jpg7.65427-39.26520.33876715.95060.2828430.405673
test00221.jpg7.37055-33.8220.32586913.75310.2828430.370918
test00231.jpg7.39534-33.9310.32703413.75310.2828430.372402
test00241.jpg7.38345-33.97950.3301413.75310.2828430.375312
test00251.jpg7.11119-31.54810.32118812.75310.2828430.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] -=15plt.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):

fromimgreg.models.radonimportRadonSolverras=RadonSolver()
ras.dot_graph()

A dependency graph representation of the RadonSolver

Tutorials

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

Documentation

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

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

Testing

Testing is done using pytest. With pytest-cov and coverage a report for the tests can be generated with:

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.

About

An image registration library for python including a simple interface for building new models.

Topics

Resources

Stars

7 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages