Skip to content

Commit

Permalink
Merge pull request #49 from clEsperanto/create-tests
Browse files Browse the repository at this point in the history
Create tests
  • Loading branch information
StRigaud authored Aug 23, 2024
2 parents 369e1d8 + 990bde2 commit c96b901
Show file tree
Hide file tree
Showing 17 changed files with 1,400 additions and 44 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ jobs:
run: sudo apt install ocl-icd-opencl-dev

- name: Build with Maven
run: mvn clean install
run: mvn clean install -DskipTests
shell: bash

- name: Run Java class (only possible on MacOS)
Expand Down
20 changes: 20 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: ClesperantoJ tests

on: [push]

jobs:
test:
runs-on: macos-13
strategy:
matrix:
java: [8, 11, 17, 21]
name: Test with Java ${{ matrix.java }}
steps:
- uses: actions/checkout@v2
- name: Setup java
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java }}
distribution: 'zulu'
- name: Execute the tests
run: mvn clean test -X
30 changes: 22 additions & 8 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,18 @@
<groupId>net.imagej</groupId>
<artifactId>ij</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
</dependencies>

<repositories>
Expand Down Expand Up @@ -294,14 +306,16 @@
</plugin>

<!-- Test plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.4.1</version>
<configuration>
<argLine>-Xmx2G</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
<forkCount>1</forkCount>
<reuseForks>false</reuseForks>
</configuration>
</plugin>

</plugins>
</build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ public static void main(String[] args) {
IJ.run(input_imp, "32-bit", "");
input_imp.show();

ArrayJ input = ImageJConverters.copyImgLib2ToArrayJ(input_imp, currentDevice, "buffer");
ArrayJ input = ImageJConverters.copyImagePlus2ToArrayJ(input_imp, currentDevice, "buffer");
ArrayJ output = Tier1.absolute(currentDevice, input, null);
ImagePlus output_imp = ImageJConverters.copyArrayJToImgLib2(output);
ImagePlus output_imp = ImageJConverters.copyArrayJToImagePlus(output);

output_imp.show();
}
Expand Down
74 changes: 51 additions & 23 deletions src/main/java/net/clesperanto/icy/IcyConverters.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import icy.image.IcyBufferedImage;
import icy.preferences.ApplicationPreferences;
import icy.preferences.GeneralPreferences;
import icy.preferences.IcyPreferences;
import icy.sequence.Sequence;
import icy.sequence.SequenceCursor;
import net.clesperanto.core.ArrayJ;
Expand All @@ -25,6 +29,12 @@
*/
public class IcyConverters {

// Icy requires that the preferences are initialized if they have not bee initialized before.
// TODO check if htey have been initialized before
static {
initIcyPreferences();
}

/** TODO extend to RandomAccessibleInterval
* Conert an {@link ArrayJ} into an ImgLib2 {@link ArrayImg} of the same dimensions and data type.
* Creates a copy of the ArrayJ in the GPU into an ArrayImg in the CPU
Expand All @@ -33,7 +43,7 @@ public class IcyConverters {
* array that is located in the GPU for clesperanto to do some operations
* @return and ImgLib2 {@link ArrayImg} on the CPU copied from the {@link ArrayJ} on the GPU
*/
public static Sequence copyArrayJToImgLib2( ArrayJ arrayj )
public static Sequence copyArrayJToSequence( ArrayJ arrayj )
{
long flatDims = arrayj.getHeight() * arrayj.getDepth() * arrayj.getWidth();
IcyDataType dataType = IcyDataType.fromString(arrayj.getDataType());
Expand Down Expand Up @@ -62,9 +72,9 @@ public static Sequence copyArrayJToImgLib2( ArrayJ arrayj )
* String "image", for buffer use "buffer"
* @return an {@link ArrayJ} copied from the {@link RandomAccessibleInterval} of the CPU
*/
public static ArrayJ copyImgLib2ToArrayJ(Sequence rai, DeviceJ device, String memoryType) {
Map<String, Integer> sizeMap = checkSize(rai);
public static ArrayJ copySequenceToArrayJ(Sequence rai, DeviceJ device, String memoryType) {
IcyDataType dataType = IcyDataType.fromIcyDataType(rai.getDataType_());
Map<String, Integer> sizeMap = checkSize(rai, dataType.getByteSize());
long totalSize = sizeMap.values().stream().reduce((int) 1L, (a, b) -> a * b);

long[] dims = sizeMap.values().stream().mapToLong(i -> (long) i).toArray();
Expand Down Expand Up @@ -98,13 +108,28 @@ private static Sequence fromBuffer(ByteBuffer byteBuffer, IcyDataType type, long
FloatBuffer floatBuff = byteBuffer.asFloatBuffer();
fillImage(im, dimensions, floatBuff::get);
break;
case INT8:
fillImage(im, dimensions, byteBuffer::get);
break;
case UINT8:
fillImage(im, dimensions, byteBuffer::get);
break;
case UINT16:
ShortBuffer uShortBuff = byteBuffer.asShortBuffer();
fillImage(im, dimensions, uShortBuff::get);
break;
case INT16:
ShortBuffer shortBuff = byteBuffer.asShortBuffer();
fillImage(im, dimensions, shortBuff::get);
break;
case INT32:
IntBuffer intBuff = byteBuffer.asIntBuffer();
fillImage(im, dimensions, intBuff::get);
break;
case UINT32:
IntBuffer uIntBuff = byteBuffer.asIntBuffer();
fillImage(im, dimensions, uIntBuff::get);
break;
default:
throw new IllegalArgumentException("Data type not supported.");
}
Expand All @@ -124,28 +149,15 @@ private static void fillImage(Sequence im, long[] dimensions, Supplier<Number> g
cursor.commitChanges();
}

private static Map<String, Integer> checkSize(Sequence imp) {
private static Map<String, Integer> checkSize(Sequence imp, long byteSize) {
Map<String, Integer> sizeMap = new LinkedHashMap<String, Integer>();
sizeMap.put("x", imp.getWidth());
sizeMap.put("y", imp.getHeight());
sizeMap.put("c", imp.getSizeC());
sizeMap.put("z", imp.getSizeZ());
sizeMap.put("t", imp.getSizeT());
sizeMap = sizeMap.entrySet().stream()
.filter(ee -> ee.getValue() == 1).collect(Collectors.toMap(ee -> ee.getKey(), ee -> ee.getValue()));
while (sizeMap.entrySet().size() > 3) {
if (sizeMap.get("t") != null)
sizeMap.remove("t");
else if (sizeMap.get("c") != null)
sizeMap.remove("c");
else if (sizeMap.get("z") != null)
sizeMap.remove("z");
}
int tot = 1;
sizeMap.put("x", imp.getWidth() == 0 ? 1 : imp.getWidth());
sizeMap.put("y", imp.getHeight() == 0 ? 1 : imp.getHeight());
sizeMap.put("z", imp.getSizeZ() == 0 ? 1 : imp.getSizeZ());
for (Integer vv : sizeMap.values()) {
tot *= vv;
byteSize *= (long) vv;
}
if (tot > Integer.MAX_VALUE)
if (byteSize > Integer.MAX_VALUE)
throw new IllegalArgumentException();
return sizeMap;
}
Expand All @@ -158,7 +170,7 @@ else if (sizeMap.get("z") != null)
* type of the sequence
* @return empty Icy sequence of the wanted type and dimensions
*/
private static Sequence createSequence(long[] dims, icy.type.DataType type)
public static Sequence createSequence(long[] dims, icy.type.DataType type)
{
while (dims.length < 3) {
long[] newArray = new long[dims.length + 1];
Expand All @@ -174,4 +186,20 @@ private static Sequence createSequence(long[] dims, icy.type.DataType type)
}
return seq;
}

/**
* Initialize the Icy meta data that is required to use Icy Sequences.
* Only initializes it if it has not been done before.
*/
public static void initIcyPreferences() {
if (ApplicationPreferences.getPreferences() == null
|| GeneralPreferences.getPreferences() == null) {
IcyPreferences.init();
}
}

public static void main(String[] args) {

createSequence(new long[] {5, 5, 5}, icy.type.DataType.FLOAT);
}
}
23 changes: 21 additions & 2 deletions src/main/java/net/clesperanto/icy/IcyDataType.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,18 @@ public enum IcyDataType {
private final icy.type.DataType icyDT;
private final Class<?> arrayClass;

public final static long MAX_UINT32 = (long) Math.pow(2, 32);

public final static int MAX_INT32 = Integer.MAX_VALUE;

public final static int MAX_UINT16 = 65536;

public final static int MAX_INT16 = 65536 / 2 - 1;

public final static int MAX_UINT8 = 256;

public final static int MAX_INT8 = 256 / 2 - 1;

IcyDataType(DataType dt, icy.type.DataType icyDT, Class<?> arrayClass) {
this.dt = dt;
this.icyDT = icyDT;
Expand Down Expand Up @@ -84,15 +96,22 @@ public void putValInArray(Object arr, int pos, Number value) {
case FLOAT32:
((float[]) arr)[pos] = value.floatValue();
break;
case UINT32:
((int[]) arr)[pos] = (int) (value.doubleValue() > Integer.MAX_VALUE ? value.doubleValue() - MAX_UINT32 : value.doubleValue());
break;
case INT32:
((int[]) arr)[pos] = value.intValue();
break;
case INT16:
case UINT16:
((short[]) arr)[pos] = (short) (value.doubleValue() > Short.MAX_VALUE ? value.doubleValue() - MAX_UINT16 : value.doubleValue());
break;
case INT16:
((short[]) arr)[pos] = value.shortValue();
break;
case INT8:
case UINT8:
((byte[]) arr)[pos] = (byte) (value.doubleValue() > Byte.MAX_VALUE ? value.doubleValue() - MAX_UINT8 : value.doubleValue());
break;
case INT8:
((byte[]) arr)[pos] = value.byteValue();
break;
default:
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/net/clesperanto/imagej/ImageJConverters.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import ij.IJ;
import ij.ImagePlus;
Expand Down Expand Up @@ -35,7 +34,7 @@ public class ImageJConverters {
* array that is located in the GPU for clesperanto to do some operations
* @return and ImgLib2 {@link ArrayImg} on the CPU copied from the {@link ArrayJ} on the GPU
*/
public static ImagePlus copyArrayJToImgLib2( ArrayJ arrayj )
public static ImagePlus copyArrayJToImagePlus( ArrayJ arrayj )
{
long flatDims = arrayj.getHeight() * arrayj.getDepth() * arrayj.getWidth();
ImageJDataType dataType = ImageJDataType.fromString(arrayj.getDataType());
Expand Down Expand Up @@ -64,8 +63,9 @@ public static ImagePlus copyArrayJToImgLib2( ArrayJ arrayj )
* String "image", for buffer use "buffer"
* @return an {@link ArrayJ} copied from the {@link RandomAccessibleInterval} of the CPU
*/
public static ArrayJ copyImgLib2ToArrayJ(ImagePlus rai, DeviceJ device, String memoryType) {
public static ArrayJ copyImagePlus2ToArrayJ(ImagePlus rai, DeviceJ device, String memoryType) {
Map<String, Integer> sizeMap = checkSize(rai, rai.getBytesPerPixel());

ImageJDataType dataType = ImageJDataType.fromImgPlusDataType(rai.getType());
long totalSize = sizeMap.values().stream().reduce((int) 1L, (a, b) -> a * b);

Expand Down Expand Up @@ -96,7 +96,7 @@ public static ArrayJ copyImgLib2ToArrayJ(ImagePlus rai, DeviceJ device, String m
}

private static ImagePlus fromBuffer(ByteBuffer byteBuffer, ImageJDataType type, long[] dimensions) {
ImagePlus im = IJ.createImage("image", (int) dimensions[0], (int) dimensions[1], (int) dimensions[2], type.createType());
ImagePlus im = IJ.createImage("image", (int) dimensions[0], (int) dimensions[1], (int) dimensions[2], type.getBitDepth());

switch (type) {
case FLOAT32:
Expand Down
14 changes: 10 additions & 4 deletions src/main/java/net/clesperanto/imagej/ImageJDataType.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,20 @@

// TODO add all types ImagePlus.GRAY8, ImagePlus.GRAY16, ImagePlus.GRAY32, ImagePlus.COLOR_256 or ImagePlus.COLOR_RGB)
public enum ImageJDataType {
FLOAT32(DataType.fromString("float"), ImagePlus.GRAY32, float[].class),
UINT16(DataType.fromString("ushort"), ImagePlus.GRAY16, short[].class),
UINT8(DataType.fromString("uchar"), ImagePlus.GRAY8, byte[].class);
FLOAT32(DataType.fromString("float"), ImagePlus.GRAY32, float[].class, 32),
UINT16(DataType.fromString("ushort"), ImagePlus.GRAY16, short[].class, 16),
UINT8(DataType.fromString("uchar"), ImagePlus.GRAY8, byte[].class, 8);

private final DataType dt;
private final int imgDtype;
private final int bitDepth;
private final Class<?> arrayClass;

ImageJDataType(DataType dt, int imgDtype, Class<?> arrayClass) {
ImageJDataType(DataType dt, int imgDtype, Class<?> arrayClass, int bitDepth) {
this.dt = dt;
this.imgDtype = imgDtype;
this.arrayClass = arrayClass;
this.bitDepth = bitDepth;
}

public static ImageJDataType fromString(String dType) {
Expand Down Expand Up @@ -53,6 +55,10 @@ public int getByteSize() {
return dt.getByteSize();
}

public int getBitDepth() {
return this.bitDepth;
}

public void readToBuffer(ArrayJ arrayj, ByteBuffer buffer) {
this.dt.readToBuffer(arrayj, buffer);
}
Expand Down
49 changes: 49 additions & 0 deletions src/test/java/TestAbsolute.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import org.junit.jupiter.api.Test;

import net.clesperanto.kernels.Tier1;
import net.clesperanto.core.MemoryJ;
import net.clesperanto.core.ArrayJ;
import net.clesperanto.core.DeviceJ;

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

import java.nio.IntBuffer;
import java.util.Arrays;

public class TestAbsolute {

@Test
public void testAbsolute() {
DeviceJ device = DeviceJ.getDefaultDevice();
ArrayJ in = MemoryJ.makeIntBuffer(device, 2, 2, 0, 2, "buffer");
in.fillMemory(-1);
ArrayJ out = MemoryJ.makeIntBuffer(device, 2, 2, 0, 2, "buffer");
out.fillMemory(-1);
Tier1.absolute(device, in, out);

int[] result = new int[4];
IntBuffer resultBuff = IntBuffer.wrap(result);
MemoryJ.readIntBuffer(out, resultBuff, 4);

assertEquals(1, Arrays.stream(result).min().getAsInt());
assertEquals(1, Arrays.stream(result).max().getAsInt());
assertEquals(1, Arrays.stream(result).average().getAsDouble());
}

@Test
public void testAbsolute1() {
DeviceJ device = DeviceJ.getDefaultDevice();
ArrayJ in = MemoryJ.makeIntBuffer(device, 2, 2, 0, 2, "buffer");
in.fillMemory(-1);
ArrayJ out = Tier1.absolute(device, in, null);

int[] result = new int[4];
IntBuffer resultBuff = IntBuffer.wrap(result);
MemoryJ.readIntBuffer(out, resultBuff, 4);

for (int val : result)
assertEquals(1, val);
in = null;
out = null;
}
}
Loading

0 comments on commit c96b901

Please sign in to comment.