Skip to content

Commit 1e413f9

Browse files
committed
ParameterConversion: various small fixes
1 parent 472ba4a commit 1e413f9

2 files changed

Lines changed: 49 additions & 35 deletions

File tree

docs/ops/doc/Concepts.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
This page is designed to help *Ops users* understand the SciJava Ops concepts powering the framework.
44

55
## Ops
6-
An **algorithm** is a mathematical routine that transforms, interrogate, or refines input values into output values. Algorithms are used throughout scientific computing, and the fundamental [purpose](Purpose.rst) of SciJava Ops is to facilitate their application.
6+
An **algorithm** is a mathematical routine that transforms, interrogate, or refines input values into output values. Algorithms are used throughout scientific computing, and the fundamental [purpose](Purpose) of SciJava Ops is to facilitate their application.
77

88
We do that by providing a framework for consistently defining and invoking algorithm implementations as **Ops**. Ops have:
99
* a **name**, establishing its purpose. An Op's name describes *what* the Op does, but not *how* the Op does it.

docs/ops/doc/ParameterConversion.rst

Lines changed: 48 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,28 @@
22
Parameter Conversion for Developers
33
========================================
44

5-
In this example, we show how Ops developers can implement parameter conversion to enable seamless interoperability between Ops utilizing different data structures.between
5+
In this example, we explain parameter conversion to a developer audience. This page provides an overview of what parameter conversion involves, how it works, and how you can enable conversion for your own data types.
66

77
Basics
88
======
99

10-
A key :ref:`value <driving-values>` of SciJava Ops is flexibility, and flexibility is (in part) achieved through **parameter conversion**. At its core, parameter conversion allows *translation* of data stored in one data structure (e.g. an ImgLib2 ``RandomAccessibleInterval``) into a different data structure (e.g. an OpenCV ``Mat``) **on the fly**. This allows SciJava Ops to execute Ops backed by OpenCV code **on ImgLib2 data structures**.
10+
A :ref:`value <driving-values>` of SciJava Ops is flexibility, and flexibility is (in part) achieved through **parameter conversion**. At its core, parameter conversion allows *translation* of data stored in one data structure (e.g. an ImgLib2 ``RandomAccessibleInterval``) into a different data structure (e.g. an OpenCV ``Mat``) **on the fly**. This allows SciJava Ops to execute Ops backed by OpenCV code **on ImgLib2 data structures**.
1111

1212
.. figure:: https://media.scijava.org/scijava-ops/1.0.1/parameter-conversion-opencv.svg
1313

1414
At matching time, parameter conversion is invoked when an Op matches a user request in name and in Op type, but differing in individual parameter types. In these situations, it looks for ``engine.convert`` Ops that could potentially convert the user's provided inputs into the required Op inputs, and the same, in the other direction, for the output.
1515

16-
A toy example
17-
=============
16+
.. _original-op:
1817

19-
Suppose we have an Op that inherently operates on ``RandomAccessibleInterval<DoubleType>``\ s:
18+
An example ``Function``
19+
=======================
20+
21+
Suppose we have a ``Function`` Op that inherently operates on ``RandomAccessibleInterval<DoubleType>``\ s:
2022

2123
.. code-block:: java
2224
2325
/**
24-
* Conolves an image with a kernel, returning the output in a new object
26+
* Convolves an image with a kernel, returning the output in a new object
2527
*
2628
* @param input the input data
2729
* @param kernel the kernel
@@ -42,36 +44,25 @@ This Op might work well, however if users have a small kernel that is *only* use
4244
4345
Img<DoubleType> in = ...
4446
// 3x3 averaging kernel
45-
double m = 1/9;
46-
double[] data = new double[] { //
47-
m, m, m, //
48-
m, m, m, //
49-
m, m, m //
47+
double[][] kernel = { //
48+
{ 1/9, 1/9, 1/9}, //
49+
{ 1/9, 1/9, 1/9}, //
50+
{ 1/9, 1/9, 1/9} //
5051
};
51-
// Not ideal
52+
// transform double[][] into a RandomAccessibleInterval
5253
Img<DoubleType> kernel = ArrayImgs.doubles(data, new long[] {3, 3});
54+
var cursor = kernel.cursor();
55+
while(cursor.hasNext())
56+
cursor.next().set(kernel[cursor.getIntPosition(0)][cursor.getIntPosition(1)]);
5357
54-
var result = ops.op("filter.convolve").input(in, kernel).apply();
55-
56-
In this case, users might find it nicer to specify their kernel as a ``double[][]``, which is much easier for users to construct
57-
58-
.. code-block:: java
59-
60-
Img<DoubleType> in = ...
61-
// 3x3 averaging kernel
62-
double m = 1/9;
63-
double[] kernel = new double[][] { //
64-
new double[] { m, m, m}, //
65-
new double[] { m, m, m}, //
66-
new double[] { m, m, m} //
67-
}
68-
69-
// Ideal case - no need to wrap to Img
70-
var result = ops.op("filter.convolve").input(in, kernel).apply();
58+
var result = ops.op("filter.convolve") //
59+
.input(in, kernel) //
60+
.outType(new Nil<RandomAccessibleInterval<DoubleType>>() {}) //
61+
.apply();
7162
72-
The only step for us as the developer is to tell SciJava Ops that it can convert ``double[][]``\ s to ``RandomAccessibleInterval<DoubleType>``\ s, which we do with ``engine.convert`` Ops.
63+
In this case, users might find it nicer to specify their kernel as a ``double[][]``, which is easier for users to construct. The only step for us as the developer is to tell SciJava Ops that it can convert ``double[][]``\ s to ``RandomAccessibleInterval<DoubleType>``\ s, which we do with ``engine.convert`` Ops.
7364

74-
A simple ``engine.convert`` Op
65+
An ``engine.convert`` Op
7566
==============================
7667

7768
All ``engine.convert`` Ops are simple ``Function``\ s, that take as input the user argument to the Op, and return a *translation* of that data into the type expected by Ops. In our case, we want to convert *from* the user's ``double[][]`` into a ``RandomAccessibleInterval<DoubleType>``:
@@ -80,8 +71,7 @@ All ``engine.convert`` Ops are simple ``Function``\ s, that take as input the us
8071
8172
/**
8273
* @param input the input data
83-
* @return an output image whose values are equivalent to {@code input}s
84-
* values but whose element types are {@link BitType}s.
74+
* @return a {@link RandomAccessibleInterval}, containing the data stored in {@code input}
8575
* @implNote op names='engine.convert', type=Function
8676
*/
8777
public static RandomAccessibleInterval<DoubleType> arrayToDoubles(final double[][] input)
@@ -98,7 +88,31 @@ All ``engine.convert`` Ops are simple ``Function``\ s, that take as input the us
9888
return img;
9989
}
10090
101-
This Op, discovered through the SciJava Ops Indexer, is **all** that is needed to make the execution pattern we want functional.
91+
This Op, discovered through the SciJava Ops Indexer, is enables the execution pattern we want.
92+
93+
.. code-block:: java
94+
95+
Img<DoubleType> in = ...
96+
// 3x3 averaging kernel
97+
double[][] kernel = { //
98+
{ 1/9, 1/9, 1/9}, //
99+
{ 1/9, 1/9, 1/9}, //
100+
{ 1/9, 1/9, 1/9} //
101+
};
102+
103+
// Ideal case - no need to wrap to Img
104+
var result = ops.op("filter.convolve") //
105+
.input(in, kernel) //
106+
.outType(new Nil<RandomAccessibleInterval<DoubleType>>() {}) //
107+
.apply();
108+
109+
At runtime, the Op matcher will invoke the following steps:
110+
111+
* The ``Img<DoubleType> input`` is left alone, as it is a ``RandomAccessibleInterval<DoubleType>``
112+
* The ``double[][] kernel`` is converted to a ``RandomAccessibleInterval<DoubleType> kernel1`` using our ``engine.convert`` Op.
113+
* The Op convolves ``input1`` with ``kernel1``, returning an ``Img<DoubleType>``
114+
* The ``RandomAccessibleInterval<DoubleType> output1`` is converted to a ``double[][] output2``
115+
* Nothing is returned
102116

103117

104118
Adding efficiency

0 commit comments

Comments
 (0)