Skip to content

Commit

Permalink
The JAMA subproject now provides its own solver implementation for im…
Browse files Browse the repository at this point in the history
…age-registration.
  • Loading branch information
Oliver-Loeffler committed Apr 24, 2023
1 parent f55c724 commit 826cbaa
Show file tree
Hide file tree
Showing 8 changed files with 322 additions and 27 deletions.
50 changes: 23 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ The solver is selected using the Java SPI (Service Provider Interface) mechanism
- [x] Versions up to and including 0.0.5 run with Java-8
- [x] Version 0.0.5 will support different linear algebra libraries (will make use of service provider API)
- [x] Version 0.0.6 will support ~~Java-8 and~~ Java-11 (~~utilize multi-release JARs~~ support for modules will be introduced)
- [ ] Version 0.0.7 will support Java-17 with records (JEP 359)
- [ ] Version 0.0.7 will no longer provide a bundle version, the core is now the `image-registration` API library. It is now mandatory to add the required solver as needed.
- [ ] Version 0.0.8 will support Java-17 with records (JEP 359)
- [ ] Later versions will support higher order calculations (first: up to 3rd order, 20 coefficient model)

These methods are used e.g. in photomask manufacturing, medical imaging or geospatial applications.
Expand All @@ -29,28 +30,22 @@ Control point or feature based methods have only limited scope of use in medical
The SNAPSHOT-API documentation is available on: https://www.raumzeitfalle.net/image-registration/api/
Version 0.0.5 is available on Maven Central using following snippet:

### Non-Modular project with JAMA backend:
### Maven Dependency for a project with JAMA backend (using `gov.nist.math:jama:1.0.3`):

```xml
<dependency>
<groupId>net.raumzeitfalle.registration</groupId>
<artifactId>image-registration</artifactId>
<version>0.0.6</version>
</dependency>
```

### Modular project with JAMA backend:


```xml
<dependency>
<groupId>net.raumzeitfalle.registration</groupId>
<artifactId>image-registration</artifactId>
<artifactId>jama-solver</artifactId>
<version>0.0.6</version>
</dependency>
```

Additionally the `module-info.java` file needs an update:
For a modular project, the projects module descriptor must be updated accordingly:

```java
module yourmodule {
Expand All @@ -70,7 +65,7 @@ module yourmodule {
</dependency>
<dependency>
<groupId>net.raumzeitfalle.registration</groupId>
<artifactId>jama-solver</artifactId>
<artifactId>la4j-solver</artifactId>
<version>0.0.6</version>
</dependency>
```
Expand All @@ -93,13 +88,14 @@ In case a custom implementaton is required, this must be created based on `solve

### Following solver implementations will be available

| Solver Module | Dependency to: | Library version: |
|-|-|-|
| `apache-math3-solver` | `org.apache.commons:commons-math3` | 3.6.1 |
| `ejml-solver` | `org.ejml:ejml-simple` | 0.41 |
| `jama-solver` | `gov.nist.math:jama` | 1.0.3 |
| `jblas-solver` | `org.jblas:jblas` | 1.2.5 |
| `la4j-solver` | `org.la4j:la4j` | 0.6.0 |
| Solver Module | Dependency to: | Library version: |
|-----------------------|-----------------------------------------------------------------------------------|-|
| `apache-math3-solver` | `org.apache.commons:commons-math3` | 3.6.1 |
| `ejml-solver` | `org.ejml:ejml-simple` | 0.41 |
| `jama-solver` | `gov.nist.math:jama` | 1.0.3 |
| `jblas-solver` | `org.jblas:jblas` | 1.2.5 |
| `la4j-solver` | `org.la4j:la4j` | 0.6.0 |
| `jama` | no external dependency, functionality is equivalent to `gov.nist.math:jama:1.0.3` | 0.6.0 |

### More Linear Algebra libraries:

Expand Down Expand Up @@ -214,19 +210,19 @@ information any kind or matrix based system can be configured.

![Models and Transforms Interfaces](docs/interfaces_models_and_transforms.png)

# Examples
# Examples (see example-modular)

There are some demos available, how this library is supposed to be used:

* `net/raumzeitfalle/registration/examples/DemoFourpointsOnlyWithMissingMeas.java`
* `net/raumzeitfalle/registration/examples/DemoFourpointsScanner.java`
* `net/raumzeitfalle/registration/examples/DemoFourpointsStandard.java`
* `net/raumzeitfalle/registration/examples/DemoMultipoint.java`
* `net/raumzeitfalle/registration/examples/DemoMultipointMagnification.java`
* `net/raumzeitfalle/registration/examples/DemoMultipointOneDimensional.java` (not yet validated)
* `net/raumzeitfalle/registration/examples/DemoMultipointResidual.java`
* `net/raumzeitfalle/registration/examples/modular/DemoFourpointsOnlyWithMissingMeas.java`
* `net/raumzeitfalle/registration/examples/modular/DemoFourpointsScanner.java`
* `net/raumzeitfalle/registration/examples/modular/DemoFourpointsStandard.java`
* `net/raumzeitfalle/registration/examples/modular/DemoMultipoint.java`
* `net/raumzeitfalle/registration/examples/modular/DemoMultipointMagnification.java`
* `net/raumzeitfalle/registration/examples/modular/DemoMultipointOneDimensional.java` (not yet validated)
* `net/raumzeitfalle/registration/examples/modular/DemoMultipointResidual.java`

The class `net.raumzeitfalle.registration.examples.Demo` is used to define all examples. This template allows it, to configure and parameterize the evaluation process as needed.
The 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.

The following example code shows, how alignment on 4 selected locations works, with
info only locations being removed. First order (scale/ortho) will be calculated on
Expand Down
4 changes: 4 additions & 0 deletions jama/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ plugins {
id 'de.jjohannes.extra-java-module-info'
}

dependencies {
implementation project(':solver-api')
}

test {
useJUnitPlatform()
}
Expand Down
5 changes: 5 additions & 0 deletions jama/src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
/**
* JAMA: A Java Matrix Package
* (also usable as a solver for image registration)
*/
open module net.raumzeitfalle.jama {
requires transitive net.raumzeitfalle.registration.solver;
exports net.raumzeitfalle.jama;

provides net.raumzeitfalle.registration.solver.spi.SolverAdapter
with net.raumzeitfalle.jama.Solver;
}
59 changes: 59 additions & 0 deletions jama/src/main/java/net/raumzeitfalle/jama/Solver.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*-
* #%L
* Image-Registration
* %%
* Copyright (C) 2019, 2021 Oliver Loeffler, Raumzeitfalle.net
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package net.raumzeitfalle.jama;

import net.raumzeitfalle.registration.solver.Deltas;
import net.raumzeitfalle.registration.solver.References;
import net.raumzeitfalle.registration.solver.Solution;
import net.raumzeitfalle.registration.solver.Solutions;
import net.raumzeitfalle.registration.solver.spi.SolverAdapter;

public class Solver implements SolverAdapter {

public Solution solve(References references, Deltas deviations) {

Matrix refs = new Matrix(references.getArray());
Matrix deltas = new Matrix(deviations.getArray(), deviations.rows());

QRDecomposition qr = new QRDecomposition(refs);

Matrix rInverse = qr.getR().inverse();
Matrix qTransposed = qr.getQ().transpose();
Matrix solution = rInverse.times(qTransposed)
.times(deltas);

double[] firstColumn = getFirstColumn(solution);
return Solutions.fromArray(firstColumn);

}

private double[] getFirstColumn(Matrix solution) {
double[] column = new double[solution.getRowDimension()];
for (int row = 0; row < column.length; row++) {
column[row] = solution.get(row, 0);
}
return column;
}

@Override
public Solution apply(References t, Deltas u) {
return solve(t, u);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
net.raumzeitfalle.jama.Solver
67 changes: 67 additions & 0 deletions jama/src/test/java/net/raumzeitfalle/jama/SolverTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*-
* #%L
* Image-Registration
* %%
* Copyright (C) 2019, 2021 Oliver Loeffler, Raumzeitfalle.net
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package net.raumzeitfalle.jama;

import net.raumzeitfalle.registration.solver.Solution;
import net.raumzeitfalle.registration.solver.spi.SolverAdapter;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class SolverTest {

private final SolverAdapter classUnderTest = new Solver();

private static final double TOLERANCE = 1E-11;

@Test
void test() {

double[][] design = {
{ -75000.0, 0.0, 0.0, -70000.0, 1.0, 0.0 },
{ 0.0, -70000.0, 75000.0, 0.0, 0.0, 1.0 },
{ -75000.0, 0.0, 0.0, 70000.0, 1.0, 0.0 },
{ 0.0, 70000.0, 75000.0, 0.0, 0.0, 1.0 },
{ 75000.0, 0.0, 0.0, 70000.0, 1.0, 0.0 },
{ 0.0, 70000.0, -75000.0, 0.0, 0.0, 1.0 },
{ 75000.0, 0.0, 0.0, -70000.0, 1.0, 0.0 },
{ 0.0, -70000.0, -75000.0, 0.0, 0.0, 1.0 } };

double[] differences = { -0.075, 0.140, -0.075, -0.140, 0.075, -0.140, 0.075, 0.140 };


Solution solution = classUnderTest.apply(() -> design, () -> differences);

double[] result = { 1.0E-6, -2.0E-6, 0.0, 0.0, 0.0, 0.0 };

assertAll(() -> assertNotNull(solution, "must not be null"),

() -> assertEquals(result[0], solution.get(0), TOLERANCE, "scale x"),
() -> assertEquals(result[1], solution.get(1), TOLERANCE, "scale y"),

() -> assertEquals(result[2], solution.get(2), TOLERANCE, "ortho x"),
() -> assertEquals(result[3], solution.get(3), TOLERANCE, "ortho y"),

() -> assertEquals(result[4], solution.get(4), TOLERANCE, "trans x"),
() -> assertEquals(result[5], solution.get(5), TOLERANCE, "trans y"));

}

}
1 change: 1 addition & 0 deletions solver-test/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ plugins {
dependencies {
implementation project(':solver-api')
implementation project(':image-registration')
testImplementation project(':jama')
testImplementation project(':jama-solver')
testImplementation project(':la4j-solver')
testImplementation project(':ejml-solver')
Expand Down
Loading

0 comments on commit 826cbaa

Please sign in to comment.