From c56e7094c5b70c9388ded7de08620cc684e9d6c0 Mon Sep 17 00:00:00 2001 From: Edward Evans Date: Sun, 16 Feb 2025 11:37:42 -0600 Subject: [PATCH 1/2] Add DefaultScaleView Op --- .../ops/image/transform/DefaultScaleView.java | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 scijava-ops-image/src/main/java/org/scijava/ops/image/transform/DefaultScaleView.java diff --git a/scijava-ops-image/src/main/java/org/scijava/ops/image/transform/DefaultScaleView.java b/scijava-ops-image/src/main/java/org/scijava/ops/image/transform/DefaultScaleView.java new file mode 100644 index 000000000..e8593b160 --- /dev/null +++ b/scijava-ops-image/src/main/java/org/scijava/ops/image/transform/DefaultScaleView.java @@ -0,0 +1,93 @@ +/*- + * #%L + * Image processing operations for SciJava Ops. + * %% + * Copyright (C) 2014 - 2025 SciJava developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ + +package org.scijava.ops.image.transform; + +import net.imglib2.Interval; +import net.imglib2.FinalDimensions; +import net.imglib2.FinalInterval; +import net.imglib2.RandomAccessibleInterval; +import net.imglib2.realtransform.InvertibleRealTransform; +import net.imglib2.realtransform.Scale; +import net.imglib2.type.numeric.NumericType; +import net.imglib2.type.numeric.RealType; + +import org.scijava.function.Functions; +import org.scijava.ops.spi.OpDependency; + +import java.util.function.BiFunction; + +/** + * @author Edward Evans + * @param image type + * @implNote op names='transform.scaleView', priority='100.' + */ + +public class DefaultScaleView & RealType> + implements BiFunction, double[], RandomAccessibleInterval> +{ + @OpDependency(name = "transform.realTransform") + private Functions.Arity3, InvertibleRealTransform, Interval, RandomAccessibleInterval> transformOp; + /** + * Image scale transformation. This Op scales input images using an array + * of scale factors per dimension. + * + * @param image the input image + * @param scaleFactors the scale factor as a list + * @return the scaled image + */ + @Override + public RandomAccessibleInterval apply( + final RandomAccessibleInterval image, + final double[] scaleFactors) + { + // get input dimensions + final long[] inputDims = image.dimensionsAsLongArray(); + + // ensure scale factor dimensions match input image dimensions + if (scaleFactors.length != inputDims.length) { + throw new IllegalArgumentException( + "Input image and scale factor dimension lengths do not match."); + } + + // initialize the scale real transform + final Scale s = new Scale(scaleFactors); + + // compute the scaled dimensions + long[] scaleDims = new long[scaleFactors.length]; + for (int i = 0; i < scaleFactors.length; i++) { + scaleDims[i] = (int) (inputDims[i] * scaleFactors[i]); + } + + // create an interval for the scaled dimensions + var scaleFinalDims = new FinalDimensions(scaleDims); + + return transformOp.apply(image, s, new FinalInterval(scaleFinalDims)); + } +} From 67a5c21b8ead6e47ed49b68fe1581db844855505 Mon Sep 17 00:00:00 2001 From: Edward Evans Date: Sun, 16 Feb 2025 20:17:05 -0600 Subject: [PATCH 2/2] WIP Lucas Kanade registration --- .../registration/LucasKanadeRegistration.java | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 scijava-ops-image/src/main/java/org/scijava/ops/image/registration/LucasKanadeRegistration.java diff --git a/scijava-ops-image/src/main/java/org/scijava/ops/image/registration/LucasKanadeRegistration.java b/scijava-ops-image/src/main/java/org/scijava/ops/image/registration/LucasKanadeRegistration.java new file mode 100644 index 000000000..748f8c2ca --- /dev/null +++ b/scijava-ops-image/src/main/java/org/scijava/ops/image/registration/LucasKanadeRegistration.java @@ -0,0 +1,116 @@ +/*- + * #%L + * Image processing operations for SciJava Ops. + * %% + * Copyright (C) 2014 - 2025 SciJava developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ + +package org.scijava.ops.image.registration; + +import net.imglib2.RandomAccessibleInterval; +import net.imglib2.type.numeric.RealType; + +import org.scijava.function.Computers; +import org.scijava.ops.spi.Nullable; +import org.scijava.ops.spi.OpDependency; + +import java.util.ArrayList; +import java.util.function.BiFunction; + +/** + * @author Edward Evans + * @param input type + * @param output type + * @implNote op names='registration.lucasKanade', priority='100.' + */ + +// TODO: write missing scaleView op +// TODO: export 'u' and 'v' optical flow array, can be used for segmentation +// TODO: consider making this Op a function and not a computer? + +public class LucasKanadeRegistration> implements + Computers.Arity7, Integer, Integer, Float, Float, Boolean, Boolean, RandomAccessibeInteger> +{ + @OpDependency(name = "transform.scaleView") + private BiFunction, double[], RandomAccessibleInterval> scaleOp; + + /** + * Lucas-Kanade image registration. This Op utilizes Lucas-Kanade's method of + * optical flow to register an image stack. + * + * @param image input 3D (X, Y, Time) image + * @param pyramidLevel maximum pyramid level to use + * @param iterations number of iterations to perform + * @param updateCoefficient template update coefficient + * @param errorTolerance error tolerance + * @param useAffine use the affine method, if false use transform + * @param logTransform boolean to set log transform + * @param output the output image + */ + + @Override + public void compute(final RandomAccessibleInterval image, + final Integer pyramidLevel, final Integer iterations, + final Float updateCoefficient, final Float errorTolerance, + final Boolean useAfffine, final Boolean logTransform, + RandomAccessibleInterval output) + { + // ensure images are 3D only + if (!(image.numDimensions() == 3)) { + throw new IllegalArgumentException( + "Input image must be 3D (X, Y, Time)."); + + // construct pyramid + long[] dims = image.dimensionsAsLongArray() + var pyramid = createScalePyramid(pyramidLevel, dims) + } + } + + /** + * Creates a scale pyramid with the specified level. + * + * @param image input image + * @param level number of pyramid levels to create + * @param shape shape of the input image + * @return the scale pyramid as a list + */ + private ArrayList> createScalePyramid(final RandomAccessibleInterval image, + final Integer level, final long[] shape) + { + var pyramid = new ArrayList>(); + double divFactor = 2.0; + double[] scaleFactors = {0.0, 0.0, 1.0}; + for (int i = 0; i < level; i++;) { + // compute scale factor, only scale X and Y + scaleFactors[0] = 1.0 / divFactor; + scaleFactors[1] = 1.0 / divFactor; + // scale image and add to the pyramid + pyramid.add(scaleOp.apply(image, scaleFactors)); + // increment division scale factor + divFactor *= 2; + + return pyramid + } + }