{"id":16701189,"url":"https://github.com/oliver-loeffler/image-registration","last_synced_at":"2025-04-10T04:10:48.634Z","repository":{"id":57737645,"uuid":"199786551","full_name":"Oliver-Loeffler/image-registration","owner":"Oliver-Loeffler","description":"Java API to perform for image registration using control points (landmarks). Supports rigid transforms and affine transforms. Decouples matrix computation from API, so use of different Java matrix computation libraries is possible.","archived":false,"fork":false,"pushed_at":"2025-02-17T22:09:46.000Z","size":3086,"stargazers_count":6,"open_issues_count":8,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-24T05:26:26.368Z","etag":null,"topics":["affine-transformation","apache-math-commons","control-points-registration","ejml","image-registration","jama","la4j","photomask","photomask-image-placement","rigid-transformations"],"latest_commit_sha":null,"homepage":"https://oliver-loeffler.github.io/image-registration/","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Oliver-Loeffler.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-07-31T05:39:18.000Z","updated_at":"2025-02-17T22:09:49.000Z","dependencies_parsed_at":"2025-01-28T19:23:27.081Z","dependency_job_id":"78059510-0e08-4634-a0e8-62ad0c9f0dd2","html_url":"https://github.com/Oliver-Loeffler/image-registration","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Oliver-Loeffler%2Fimage-registration","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Oliver-Loeffler%2Fimage-registration/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Oliver-Loeffler%2Fimage-registration/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Oliver-Loeffler%2Fimage-registration/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Oliver-Loeffler","download_url":"https://codeload.github.com/Oliver-Loeffler/image-registration/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248154987,"owners_count":21056543,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["affine-transformation","apache-math-commons","control-points-registration","ejml","image-registration","jama","la4j","photomask","photomask-image-placement","rigid-transformations"],"created_at":"2024-10-12T18:43:06.649Z","updated_at":"2025-04-10T04:10:48.604Z","avatar_url":"https://github.com/Oliver-Loeffler.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Image Registration using Control Points\n\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) \n\nImage Registration API:\n\n[![Javadocs](https://www.javadoc.io/badge/net.raumzeitfalle.registration/image-registration.svg)](https://www.javadoc.io/doc/net.raumzeitfalle.registration/image-registration) [![Maven Central](https://img.shields.io/maven-central/v/net.raumzeitfalle.registration/image-registration)](https://search.maven.org/search?q=net.raumzeitfalle.registration) [![GitHub issues](https://img.shields.io/github/issues/oliver-loeffler/image-registration)](https://github.com/Oliver-Loeffler/image-registration/issues) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=net.raumzeitfalle.registration%3Aimage-registration\u0026metric=coverage)](https://sonarcloud.io/summary/new_code?id=net.raumzeitfalle.registration%3Aimage-registration)\n\nSolver-API: \n\n[![Javadocs](https://www.javadoc.io/badge/net.raumzeitfalle.registration/image-registration.svg)](https://www.javadoc.io/doc/net.raumzeitfalle.registration/solver-api)\n\n## TL;DR;\n\nImage registration is the process of finding the transform to match a given image with a desired reference. This library supports rigid body transforms (translation and rotation) as well as affine transforms (anisotropic scaling, anisotropic rotation/shear aka. non-orthogonality). Currently non-linear transforms are not supported.\n\nUp to version 0.0.4, this API only worked together with NIST JAMA. Since version 0.0.5, different linear algebra frameworks can be used in `image-registration` using the Solver-API. Here it is now possible to choose either `gov.nist.math.jama`, \n`org.la4j`, `org.ejml`, `org.apache.commons.math3` or even `org.jblas`. The library now consists of an API and a core JAR and a group of JARs providing a solver implementation for the linear algebra framework of choice. \nThe solver is selected using the Java SPI (Service Provider Interface) mechanism. With version 0.0.7, selection of a solver implementation is mandatory as the main artifact no longer includes a default solver implementation.\n\n- [x] Versions up to and including 0.0.5 run with Java-8\n- [x] Version 0.0.5 will support different linear algebra libraries (will make use of service provider API)\n- [x] Version 0.0.6 will support ~~Java-8 and~~ Java-11 (~~utilize multi-release JARs~~ support for modules will be introduced)\n- [x] Version 0.0.7 will no longer provide a bundle version, the core is now the `image-registration` API library. It will be mandatory to add the required solver as needed.\n- [ ] Version 0.0.8 will support Java-17 with records (JEP 359)\n- [ ] Later versions will support higher order calculations (first: up to 3rd order, 20 coefficient model)\n\nThese methods are used e.g. in photomask manufacturing, medical imaging or geospatial applications.\nControl point or feature based methods have only limited scope of use in medical imaging, there intensity based or voxel based methods are preferred due to the natural structure of medical image data. These additional intensity and voxel based methods are not supported by this library.\n\n* Photomask related:http://www.lithoguru.com/scientist/glossary/R.html#registration, http://www.lithoguru.com/scientist/glossary/O.html#overlay,  https://www.nist.gov/system/files/documents/pml/div683/conference/Hughes.pdf\n* Medical imaging: http://www.iro.umontreal.ca/~sherknie/articles/medImageRegAnOverview/brussel_bvz.pdf\n* Geo-Registration: http://www.georeference.org/doc/georegistration.htm \n* Chris A. Macks Youtube Channel: https://www.youtube.com/@ChrisMack\n\n## How to start?\n\nThe SNAPSHOT-API documentation is available on: https://www.raumzeitfalle.net/image-registration/reg/\nThe javadoc for the Solver-API: https://www.raumzeitfalle.net/image-registration/solver/\n\nVersion 0.0.7 is available on Maven Central using following snippet:\n\n### Maven Dependency for a project with JAMA backend (using `gov.nist.math:jama:1.0.3`):\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003enet.raumzeitfalle.registration\u003c/groupId\u003e\n  \u003cartifactId\u003eimage-registration\u003c/artifactId\u003e\n  \u003cversion\u003e0.0.7\u003c/version\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n  \u003cgroupId\u003enet.raumzeitfalle.registration\u003c/groupId\u003e\n  \u003cartifactId\u003ejama-solver\u003c/artifactId\u003e\n  \u003cversion\u003e0.0.7\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nFor a modular project, the projects module descriptor must be updated accordingly:\n\n```java\nmodule yourmodule {\n\trequires net.raumzeitfalle.registration.solver;\n\trequires net.raumzeitfalle.registration.core;\n\tuses net.raumzeitfalle.registration.solver.SolverProvider;\n}\n```\n\n### Modular project with any custom backend:\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003enet.raumzeitfalle.registration\u003c/groupId\u003e\n  \u003cartifactId\u003esolver-api\u003c/artifactId\u003e\n  \u003cversion\u003e0.0.7\u003c/version\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n  \u003cgroupId\u003enet.raumzeitfalle.registration\u003c/groupId\u003e\n  \u003cartifactId\u003ela4j-solver\u003c/artifactId\u003e\n  \u003cversion\u003e0.0.7\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nThe artifact `image-registration` provides the actual API for image registration using control points. The `solver-api` artifact defines the service provider interface which is required to integrate different externa linear algebra (LA) libraries. The third artifact in this example, `jama-solver` provides an implementation to the `solver-api` based on NIST JAMA library. \n\nWhen the consumer project requires a different LA library, the appropriate implementation provided by this project can be used.\nIn case a custom implementaton is required, this must be created based on `solver-api`.\n\n### New API structure\n\n| Module                      | Purpose                                                                                                                |\n|-----------------------------|------------------------------------------------------------------------------------------------------------------------|\n| `image-registration`        | Image Registration API without any external solver binding                                                             |\n| `solver-api`                | API to utilize different linear algebra frameworks for calculation                                                     |\n| `solver-test`               | Non-API, project to test numerics and service discovery of all available solvers                                       |\n| `example-non-modular`       | Non-API, A Gradle example project on how to use this library in classical classpath based Java project aka. non-modular |\n| `example-modular`           | Non-API, The same example project but implemented using the module path aka. a modular project.                        |\n| `jama`                      | Non-API, Fork of NIST JAMA: Java Matrix Package, based on version 1.0.3                                                |\n\n### Following solver implementations will be available\n\n| Solver Module         | Dependency to:                                                                    | Library version: |\n|-----------------------|-----------------------------------------------------------------------------------|-|\n| `apache-math3-solver` | `org.apache.commons:commons-math3`                                                | 3.6.1 |\n| `ejml-solver`         | `org.ejml:ejml-simple`                                                            | 0.41 |\n| `jama-solver`         | `gov.nist.math:jama`                                                              | 1.0.3 |\n| `jblas-solver`        | `org.jblas:jblas`                                                                 | 1.2.5 |\n| `la4j-solver`         | `org.la4j:la4j`                                                                   | 0.6.0 |\n| `jama`                | no external dependency, functionality is equivalent to `gov.nist.math:jama:1.0.3` | 0.6.0 |\n\n### More Linear Algebra libraries:\n\n* https://ojalgo.org/\n* https://dst.lbl.gov/ACSSoftware/colt/\n* https://github.com/fommil/matrix-toolkits-java\n* https://github.com/deeplearning4j/nd4j\n* https://math.nist.gov/javanumerics/jama/\n\n\n## Goals\n\n- [ ] Learn how to implement a construction kit for various transforms used in photomask image placement \n  using Javas functional elements (enabling use of .andThen(...) and .compose(...)\n- [ ]  Experimenting to find suitable data types and data flows for easy use and extendability\n- [ ]  Try to make model parameter names and class names to speak for themselves, ideally \n  end up with a fluent API which uses builder pattern for setup\n- [ ]  The library should behave as lazy as possible \n- [ ]  It should be numerically and technically correct \n- [ ]  Try more advanced transforms beyond rigid (alignment) and affine (6-parameter first \n  order). Technically n-parameters higher order should work.\n- [x]  Decouple matrix computation (equation solving) from high level transform code so \n  that matrix libraries can be exchanged (e.g. using La4J instead of Jama)\n- [ ]  Make all core elements immutable, improve design step by step to achieve concurrency \n  for large data sets (improve speed by using fork-join, try to use async using CompletableFutures) \n- [ ]  Consider use of Units-of-Measurement API (JSR385, http://unitsofmeasurement.github.io/unit-api/)\n- [ ]  Utilize records where possible (JEP359, https://openjdk.java.net/jeps/359)\n\n## Todos\n\n* Handle 1D cases (handling of individual missing points already works)\n* Define high level API (ideally fluent or builder based) to compose evaluations.\n* Fluent-API for selecting specific displacements for alignment, positional calculation, \n  first order calculation\n* Implement higher order polynomial model with configurable coefficients (polynomial \n  model should work up to 9th order, coefficients to be used shall be configurable independently for x and y)\n* Sum up learnings and reshape structure of alignment/correction classes, possibly add \n  higher level functions to do the all-in-one-job as its done in the demos.\n* Add graphical examples of first order distortions.\n* Functionality to determine which kind of correction / model can be used on a given dataset\n\n# How does is work?\n\n## Processing steps\n\n![Steps to registration correction](docs/process_flow.png)\n\n## Concepts\n\n* Image registration\n* Displacement\n* Rigid Body Transform\n* Affine Transform\n* Alignment and First Order Distortions\n* FirstOrderSetup\n* FirstOrderCorrection\n* FirstOrderResult\n\n## Domain types\n\n* Displacement\n\n* Category\n* SiteSelection\n    * AlignmentSelection\n    * CalculationSelection\n\n* Transform (high level)\n    * RigidTransform\n    * AffineTransform\n    * SimilarityTransform\n    * NonUniformSimilarityTransform\n    * HighOrderTransform (not yet implemented)\n      \n* TransformCorrection\n    * SkipTransform\n    * SkippableOperation\n\n* Transform (low level)\n    * ModelEquation\n    * TransformModel\n    * Dimension\n    * Orientation\n    * SpatialDistribution\n    * Distribution\n\n## Interfaces\n\n### Transforms\n\nTransforms are used to manipulate displacement elements. Depending on the model used, \nthere may exist different transform types and implementations. Each transform is a \n`Function` which, applied to a `Displacement`, will return a `Displacement`. There \nare currently two base transforms, the `RigidTransform` and the `AffineTransform`. \nWhen transforms are parameterized in a way that there will be actually no change to \nthe displacement data, then in some cases a `SkipTransform` might be created and used. \nA `SkipTransform` must not perform any calculations, instead it must pass through the \ngiven data without any modifications.\n\n![Transforms Interfaces](docs/interfaces.png)\n\n### Transform Models\n\nOne idea and goal is, to make the underlying transformation models exchangeable. Therefore \nthe `RigidBodyModel` and the `AffineModel` interfaces exist. The idea is to make the \nactual calculation algorithm exchangeable whereas the code used in an applications \nshall remain unchanged.\nThe models are technically bi-functions which consume a `Collection` of equation objects \n(`\u003cT extends Orientable\u003e`) and a `Dimension` instance. The `Dimension` instance holds the\ninformation how many X,Y locations exist and how the data is oriented (e.g. 1D one-dimensional, \neither X or Y or 2D two-dimensional X and Y). Using the equations and the dimensional \ninformation any kind or matrix based system can be configured.\n\n![Models and Transforms Interfaces](docs/interfaces_models_and_transforms.png)\n\n# Examples (see example-modular)\n\nThere are some demos available, how this library is supposed to be used:\n\n* `net/raumzeitfalle/registration/examples/modular/DemoFourpointsOnlyWithMissingMeas.java`\n* `net/raumzeitfalle/registration/examples/modular/DemoFourpointsScanner.java`\n* `net/raumzeitfalle/registration/examples/modular/DemoFourpointsStandard.java`\n* `net/raumzeitfalle/registration/examples/modular/DemoMultipoint.java`\n* `net/raumzeitfalle/registration/examples/modular/DemoMultipointMagnification.java`\n* `net/raumzeitfalle/registration/examples/modular/DemoMultipointOneDimensional.java` (not yet validated)\n* `net/raumzeitfalle/registration/examples/modular/DemoMultipointResidual.java`\n\nThe class `net.raumzeitfalle.registration.examples.modular.Demo` is used to define all examples. This template allows it, to configure and parameterize the evaluation process as needed. \n\nThe following example code shows, how alignment on 4 selected locations works, with \ninfo only locations being removed. First order (scale/ortho) will be calculated on \nall locations. To calculate first order on selected locations, `Alignments.SCANNER_SELECTED` must \nbe used.\n\n```java\n    \n    /* STEP 1, load displacements from file (or any other source)\n     *\n     * The CSV file may look like:\n     * \"refx\",\"refy\",\"posx\",\"posy\",\"diffx\",\"diffy\",\"type\"\n     * 10980.0,9012.5,10980.014331404400,9012.481628831100,0.014331404400,-0.018371168900,\"ALIGN\"\n     * 10980.0,73512.5,10980.009388937700,73512.484174799200,0.009388937700,-0.015825200800,\"REG_MARK\"\n     * 10980.0,143387.5,10980.004598393400,143387.490394277000,0.004598393400,-0.009605722700,\"ALIGN\"\n     * ....\n     * 146975.0,14925.0,146975.030283248000,NaN,0.030283248900,NaN,\"INFO_ONLY\"\n     * \n     * All values are stored with the same unit, in this example all columns consist\n     * of values in microns. The values in columns (diffx,diffy) are not used.\n     * In case of one-dimensionality or missing values, NaN can be used.\n     * \n     */\n\n    List\u003cDisplacement\u003e displacements = new FileLoader().load(Paths.get(\"Demo-4Point.csv\"));\n        \n    /*\n     * \n     * Each Displacement consists of a design location (x,y) and the actual displaced\n     * location (xd,yd). By default, each Displacement is of type REG, but depending\n     * on declaration in CSV file, a different DisplacementClass can be assigned.\n     * The DisplacementClass allows to create simple predicates to select Displacmemt  \n     * instances for different operations.\n     *\n     */\n    \n\n    // STEP 2, perform site selection\n    Predicate\u003cDisplacement\u003e allSites = d-\u003etrue;\n     \n    SiteSelection selection = SiteSelection\n                        .forAlignment(d -\u003e d.isOfType(DisplacementClass.ALIGN))\n                        .forCalculation(allSites)\n                        .forRemoval(d-\u003ed.isOfType(DisplacementClass.INFO_ONLY));\n    \n    // STEP 3, parametrize evaluation model \n    FirstOrderSetup setup = FirstOrderSetup\n                        .usingAlignment(Alignments.SELECTED)\n                        .withCompensations(Compensations.SCALE, Compensations.ORTHO)\n                        .withSiteSelection(selection);\n\n    // STEP 4, perform correction and calculate results\n    FirstOrderResult result = FirstOrderCorrection.using(displacements, setup);\n    Collection\u003cDisplacement\u003e results = result.getDisplacements();\n\n    /* \n     *  Alternatively:\n     *\n     *  FirstOrderCorrection correction = new FirstOrderCorrection();\n     *  results = correction.apply(displacements, setup).getDisplacements();\n     * \n     *  As FirstOrderCorrection is a function, .andThen(...) and .compose(...) \n     *  can be used as well. \n     *\n     */  \n    \n    // STEP 5, print results\n        \n    // Now print results before correction\n    DisplacementSummary uncorrectedSummary = Displacement.summarize(displacements, selection.getCalculation());\n    System.out.println(uncorrectedSummary);\n        \n    // after correction\n    DisplacementSummary correctedSummary = Displacement.summarize(results, selection.getCalculation());\n    System.out.println(correctedSummary);\n        \n    // now also print residual first order and alignment\n    RigidTransform correctedAlignment = result.getAlignment();\n    System.out.println(correctedAlignment);\n        \n    AffineTransform correctedFirstOrder = result.getFirstOrder();\n    System.out.println(correctedFirstOrder);\n```\n\n## Transform types\n\n| Symbol | Description                                                      |\n| ------ | ---------------------------------------------------------------- |\n|    +   | is directly calculated by model                                  |\n|    o   | can be approximated from results                                 |\n|  sx/sy | anisotropic scaling (scale x/y)                                  |\n|   mag  | magnification, isotropic scaling (mag = average(sx,sy))          |\n|  ox/oy | anisotropic rotation (shearing or non-orthogonality, ortho x/y)  |\n|  ortho | isotropic non-orthogonality (ortho = oy - ox)                    |\n|   rot  | isotropic rotation                                               |\n|  tx/ty | translation in x/y direction                                     |\n\n\n| Transform              | tx  | ty  | sx  | sy  | mag | ox  | oy  | ortho | rot |\n| ---------------------- | --- | --- | --- | --- | --- | --- | --- | ----- | --- |\n| Rigid                  | +   | +   |     |     |     |     |     |       |  +  |\n| Affine                 | +   | +   | +   | +   | o   | +   | +   | +     |  o  |\n| Similarity             | +   | +   |     |     | +   |     |     | o     |  +  |\n| Non-Uniform Similarity | +   | +   | +   | +   | o   |     |     | o     |  +  |\n\n\n## Cases\n\n### #1 common case, references and readings in 2D (X,Y)\n\n![2D references with readings in XY](docs/images/01_reference-2D_readings-XY.png)\n\n| Direction | Refs | Readings |\n| --------- | -----| -------- |\n| X (count) | \u003e 1  | \u003e 1      |\n| Y (count) | \u003e 1  | \u003e 1      |\n\n* Input: X,Y,Xd,Yd\n* Result: tx,ty,sx,sy,ox,oy\n\n### #2 special case, references 2D, readings 1D (X)\n\n![2D references with readings in X](docs/images/02_reference-2D_readings-X.png)\n\n| Direction | Refs | Readings |\n| --------- | -----| -------- |\n| X (count) | \u003e 1  | \u003e 1      |\n| Y (count) | \u003e 1  | = 0      |\n\n* Input: X,Y,Xd\n* Result: tx,sx,ox\n\n### #3 special case, references 2D, readings 1D (Y)\n\n![2D references with readings in Y](docs/images/03_reference-2D_readings-Y.png)\n\n| Direction | Refs | Readings |\n| --------- | -----| -------- |\n| X (count) | \u003e 1  | = 0      |\n| Y (count) | \u003e 1  | \u003e 1      |\n\n* Input: X,Y,Yd\n* Result: ty,sy,oy\n\n### #4 common case, references in 2D, most readings (X,Y), *some readings (X or Y)*\n\n![2D references with partially missing X or Y](docs/images/04_reference-2D_readings-XY-partial-X-Y.png)\n\n| Direction | Refs | Readings |\n| --------- | -----| -------- |\n| X (count) | \u003e 1  | \u003e 1      |\n| Y (count) | \u003e 1  | \u003e 1      |\n\n* Input: X,Y,Xd,Yd; __*some readings have either Xd or Yd only*__\n* Result: tx,ty,sx,sy,ox,oy\n\n### #5 special case, references along horizontal line, readings in 2D (X,Y)\n\n![references along horizontal line (1D) with X and Y](docs/images/05_reference-1D-hor_readings-XY.png)\n\n| Direction | Refs | Readings |\n| --------- | -----| -------- |\n| X (count) | \u003e 1  | \u003e 1      |\n| Y (count) | = 1  | \u003e 1      |\n\n* Input: X,Y,Xd,Yd\n* Result: tx,ty,sx,ox\n\n### #6 special case, references along vertical line, readings in 2D (X,Y)\n\n![references along vertical line (1D) with X and Y](docs/images/06_reference-1D-ver_readings-XY.png)\n\n| Direction | Refs | Readings |\n| --------- | -----| -------- |\n| X (count) | = 1  | \u003e 1      |\n| Y (count) | \u003e 1  | \u003e 1      |\n\n* Input: X,Y,Xd,Yd\n* Result: tx,ty,sy,oy\n\n### #7 special case, references along horizontal line, readings in 1D (X)\n\n![references along horizontal line (1D) with X only](docs/images/07_reference-1D-hor_readings-X.png)\n\n| Direction | Refs | Readings |\n| --------- | -----| -------- |\n| X (count) | \u003e 1  | \u003e 1      |\n| Y (count) | = 1  | = 0      |\n\n* Input: X,Y,Xd\n* Result: tx,sx\n\n### #8 special case, references along horizontal line, readings in 1D (Y)\n\n![references along horizontal line (1D) with Y only](docs/images/08_reference-1D-hor_readings-Y.png)\n\n| Direction | Refs | Readings |\n| --------- | -----| -------- |\n| X (count) | \u003e 1  | = 0      |\n| Y (count) | = 1  | \u003e 1      |\n\n* Input: X,Y,Yd\n* Result: ty,ox\n\n### #9 special case, references along vertical line, readings in 1D (X)\n### #10 special case, references along vertical line, readings in 1D (Y)\n### #11 special case, only one reference position, readings in (X and Y) or (X or Y)\n\n![references on one single location, partially with X and Y, some XY](docs/images/11_single-reference-singularity.png)\n\n## Distortion Types Overview (incomplete)\n\n### Noise and No-Noise\n![Perfect](example-non-modular/distortions_none.png)\n![Noise only](example-non-modular/distortions_noise_only.png)\n\n### Translation\n![translation x](example-non-modular/distortions_translation_x.png)\n![translation y](example-non-modular/distortions_translation_y.png)\n![translation xy](example-non-modular/distortions_translation_xy.png)\n\n### Scaling\n![shrink x](example-non-modular/distortions_scaling_shrink_x.png)\n![extend x](example-non-modular/distortions_scaling_extend_x.png)\n\n![shrink y](example-non-modular/distortions_scaling_shrink_y.png)\n![extend y](example-non-modular/distortions_scaling_extend_y.png)\n\n![shrink xy](example-non-modular/distortions_scaling_shrink_xy.png)\n![extend xy](example-non-modular/distortions_scaling_extend_xy.png)\n\n### Skew\n![skew x](example-non-modular/distortions_skew_x.png)\n![skew y](example-non-modular/distortions_skew_y.png)\n![skew xy](example-non-modular/distortions_skew_xy.png)\n\n![skew -x](example-non-modular/distortions_skew_x_inv.png)\n![skew -y](example-non-modular/distortions_skew_y_inv.png)\n![skew -x,-y](example-non-modular/distortions_skew_xinv_yinv.png)\n\n![skew x -y](example-non-modular/distortions_skew_x_yinv.png)\n![skew -x y](example-non-modular/distortions_skew_xinv_y.png)\n\n### Combination\n\n![scaling and shifting](example-non-modular/distortions_scaling_shifting_xy.png)\n![scaling, shifting, noise](example-non-modular/distortions_noisy_scaling_shifting_xy.png)\n![scaling, shifting, skew, noise](example-non-modular/distortions_noisy_scaling_shifting_skew_xy.png)\n\n### Higher Order\n\n![scaling, skew, high order](example-non-modular/distortions_higher_order_xy.png)\n![scaling, skew, noise, high order](example-non-modular/distortions_higher_order_noise_xy.png)\n\n\n\n# References for further reading\n\n## Links\n\n* https://www.fil.ion.ucl.ac.uk/spm/doc/books/hbf2/pdfs/Ch2.pdf\n* https://www.uni-muenster.de/AMM/num/Vorlesungen/VarBioMed_WS10/skript/Kapitel_3_4_Registrierung.pdf\n* http://www.mathe.tu-freiberg.de/~tochten/gkhm/skript_Matrizen_Gleichungssysteme_Determinanten_ws07.pdf\n* https://www.cs.tau.ac.il/~dcor/Graphics/cg-slides/trans3d.pdf \n\n# License\n\n## Apache License, Version 2.0 \n\nCopyright 2019 Oliver Löffler, Raumzeitfalle.net\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\n## Attributions, external libraries used with their licenses\n\nThis project makes use of NIST.gov JAMA library. JAMA is public domain, see:\nhttps://math.nist.gov/javanumerics/jama/#license.\n\nAlso, this project uses LA4J library, which also follows Apache 2.0 license.\nSee http://la4j.org for details, sources can be found at https://github.com/vkostyukov/la4j.\n\nBadges have been created with:\n\n* https://www.javadoc.io\n* https://shields.io\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foliver-loeffler%2Fimage-registration","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foliver-loeffler%2Fimage-registration","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foliver-loeffler%2Fimage-registration/lists"}