soil-align

Command line tool

How to use

Soil-align application has a command line interface. If you launch it without arguments the following short help appears:

% soil-align
Abrupt ending of the input: argument #<ARGUMENT {11004A6423}> missing
Usage: soil-align [-v|--verbose] [-t|--threads N] [-w|--workspace-side S]
                  [-O|--transform-output m.npy] [-o|--output out.npy]
                  [--rotation-constraint AXIS] [-s|--scaling]
                  [-b|--background-color COLOR] [--dist-ratio C]
                  [--fit-error E] [--ransac-iterations M]
                  reference source

Description of flags and options
--ransac-iterations M           Number of RANSAC iterations
--fit-error E                   The maximal allowed fit error to treat a sample as inlier
--dist-ratio C                  Controls what we consider a match
-b|--background-color COLOR     Background color
-s|--scaling                    Add uniform scaling to the model
--rotation-constraint AXIS      Constrain rotation to be around only one axis (0, 1 or 2)
-o|--output out.npy             Output file name for a transformed image (.npy or .raw)
-O|--transform-output m.npy     Output file name for a transform matrix (.npy)
-w|--workspace-side S           Side of a workspace which is cut from center of the input images
-t|--threads N                  Number of threads to use
-v|--verbose                    Be verbose

Two mandatory arguments reference and source are two input images. Soil-align will try to bring a source image into a reference' coordinate system and write a result image (if -o option is specified) and/or write a transform matrix (if -O option is specified). The transform matrix is 4×4 matrix in Numpy format which when left-multiplied by an augmented coordinate vector \((x, y, z, 1)^T\) in the reference' coordinate system produces a coordinate vector \((x', y', z', 1)^T\) in the source' coordinate system.

Here we discuss not-so-important options:

  • -v — Be more verbose
  • -t — Number of threads. Used when computing image feature points and matching descriptors. On FreeBSD platform the default is a half of available cores, but no more than 10. On other platforms the default is 1.
  • -w — Used to crop a big input image. When not specified the whole image is used to compute feature points. When specified, a window of this side is cut from the center of an image. Feature points are only found in this window
  • --rotation-constraint — When finding a transform between the reference' and source' coordinate systems constrain possible rotations, so only a rotation around this axis (0, 1 or 2) is allowed. When not specified, all rotations are allowed. Numeration of axes is in row-major order (i.e. if an array a[i, j ,k] is a pixel in your image, then i is the 0th index, j is the 1st index and k is the 3rd index)
  • -s — Allow scaling (assume the images are of different resolution) when finding a transform between the reference' and source' coordinate systems. This feature is experimental and is turned off by default.
  • -b — What color to use for out-of-bounds array access. Used to produce the resulting image. Can range from 0 to 255.
  • --dist-ratio — Feature points are matched using 2-nearest neighbors according to Euclidean distance between corresponding descriptors. Two points \(p_{ref}\) and \(p_{src}\) match if \(d \rho(p_{ref}, p_{src}) < \rho(p_{ref}, p'_{src})\). Here \(p'_{src}\) is the second-nearest feature point and \(d\) is the distance ratio. The default value is 1.2
  • --fit-error — A parameter used in the RANSAC algorithm to determine if a model fits a point. The default value is 100.0
  • --ransac-iterations — A number of RANSAC iterations to find a model which fits the feature points. The default value is 5000.

Soil-align utilises LMDB to store image descriptors. The DB is written at ~/.local/share/soil-align/ by default, but the path can be overwritten with SOIL_ALIGN_DB environment variable. The DB accelerates registration within the same dataset. After working with the dataset it's recommended to manually remove the database. No DB pruning or what else to reduce the DB size is implemented at the moment.

Output explained

A typical output of soil-align when being run with -v option is the following:

 <INFO> [15:01:00] soil-align/cli cli.lisp (top level form %main) - Starting
 <INFO> [15:01:00] soil-align/cli cli.lisp (top level form %main) -
  Will use 6 threads
 <INFO> [15:17:13] soil-align/cli cli.lisp (top level form %main log-eval) -
  SOIL-ALIGN/CLI::MESSAGE: "Got descriptors of the source image"
 <INFO> [15:34:03] soil-align/cli cli.lisp (top level form %main log-eval) -
  SOIL-ALIGN/CLI::MESSAGE: "Got descriptors of the reference image"
 <INFO> [15:36:00] soil-align/cli cli.lisp (top level form %main) -
  Found matches between images
 <INFO> [15:36:00] soil-align/cli cli.lisp (top level form %main) -
  Found a transform matrix
 <INFO> [15:36:12] soil-align/cli cli.lisp (top level form %main log-eval) -
  SOIL-ALIGN/CLI::MESSAGE: "Computed a transformed image"
 <INFO> [15:36:12] soil-align/cli cli.lisp (top level form %main) -
  Summary: 281390/300000 descriptors, 379 independent parameters, 996 matches, 842 inliers, 805.0559 fit error

As you can see it took 35 minutes to process a pair of images. In this example a workspace size of 800 were used. Each image contains about 300000 feature points but there are only 996 matches between images. This is because there was a process of drying between the images which changed the structure of the porous medium. Nevertheless soil-align was able to register the images. It constructed a transform which fitted 842 descriptors with total error of 805 (the error is computed as \(\sqrt{\sum_i |T(x_i) - y_i|^2}\)) where \(x_i\) is a coordinate of a feature point on the source image, \(y_i\) is a coordinate of a feature point on the reference image and \(T\) is a transform between source and reference coordinate systems.

If you run soil-align again with the same reference image, the execution time is reduced to 17 minutes due to use of LMDB.

 <INFO> [15:59:34] soil-align/cli cli.lisp (top level form %main) - Starting
 <INFO> [15:59:34] soil-align/cli cli.lisp (top level form %main) -
  Will use 6 threads
 <INFO> [16:15:09] soil-align/cli cli.lisp (top level form %main log-eval) -
  SOIL-ALIGN/CLI::MESSAGE: "Got descriptors of the source image"
 <INFO> [16:15:16] soil-align/cli cli.lisp (top level form %main log-eval) -
  SOIL-ALIGN/CLI::MESSAGE: "Got descriptors of the reference image"
 <INFO> [16:17:00] soil-align/cli cli.lisp (top level form %main) -
  Found matches between images
 <INFO> [16:17:02] soil-align/cli cli.lisp (top level form %main) -
  Found a transform matrix
 <INFO> [16:17:13] soil-align/cli cli.lisp (top level form %main log-eval) -
  SOIL-ALIGN/CLI::MESSAGE: "Computed a transformed image"
 <INFO> [16:17:14] soil-align/cli cli.lisp (top level form %main) -
  Summary: 251890/300000 descriptors, 379 independent parameters, 2025 matches,
 1868 inliers, 1068.2292 fit error

Supported formats

  • Numpy arrays (.npy files). These arrays must have rank 3 and dtype 'uint8'. Elements of an array encode pixel intensity at the point.
  • Multipage TIFF images. Each image in a multipage file must have the same dimensions. Multipage images can be easily created and split into multiple one-page tiff images with tiffcp and tiffsplit command line tools shipped with libtiff.
  • Raw files (not recommended!)

To use raw files (once again: not recommended!) you need to create a metadata file with extension s-exp for each input file. It contents should be:

(quoted-name-of-raw-file dim-x dim-y dim-z)

for example

("foo.raw" 1000 1000 600)

It is expected that raw file has its content in row-major order with one unsigned octet per voxel. For output files you don't need metadata (dimensions of the output = dimensions of the source).