Docs
Search…
Java Example
In this tutorial you create a Java module which applies the Canny Edge Detector to an image.

Java Example Module

Writing the module

Below you see an overview of the files we will generate for this tutorial. As required by Java and Maven our module has the following folder structure.
1
├── Dockerfile
2
├── README.md
3
├── canny
4
│ ├── pom.xml
5
│ └── src
6
│ └── main
7
│ └── java
8
│ └── com
9
│ └── zeiss
10
│ └── apeer
11
│ └── modules
12
│ └── App.java
13
└── module_specification.json
Copied!
Derived from the module specification - the WFE_INPUT_JSON environment variable contains something similar to the following.
1
{
2
"input_image": "/input/module_0_0/image.png",
3
"WFE_output_params_file": "wfe_module_params_1_1.json"
4
}
Copied!
This is what our Java program needs to work with.
As specified by the input - we need to create a results file in /output/wfe_module_params_1_1.json. This file needs to contain content similar to the following.
1
{
2
"output_image": "/output/output_image.jpg"
3
}
Copied!
As you can see we're storing the resulting image in /output/output_image.jpg. Keep in mind that writing the output file is required if output is defined in your module specification. Otherwise the module execution will fail.
This is a very basic example utilizing the openimaj Java library. It is based on their tutorials. Below you can see the source code of ApeerMain.java and EdgeDetection.java. The former code is executed first and calls the EdgeDetection class.
ApeerMain.java
EdgeDetection.java
1
package com.apeer.modules;
2
3
import com.apeer.sdk.ApeerDevKit;
4
import com.apeer.sdk.ApeerEnvironmentException;
5
import com.apeer.sdk.ApeerInputException;
6
import com.apeer.sdk.ApeerOutputException;
7
8
public class ApeerMain {
9
public static void main(String[] args) {
10
try {
11
var adk = new ApeerDevKit();
12
var inputImagePath = adk.getInput("input_image", String.class);
13
14
var outputs = new EdgeDetection().run(inputImagePath);
15
16
adk.setFileOutput("output_image", (String) outputs.get("output_image"));
17
adk.finalizeModule();
18
19
} catch (ApeerEnvironmentException | ApeerInputException | ApeerOutputException e) {
20
System.out.println(e.getMessage());
21
System.out.println(e.getStackTrace());
22
}
23
}
24
}
Copied!
1
package com.apeer.modules;
2
3
import org.openimaj.image.ImageUtilities;
4
import org.openimaj.image.processing.edges.CannyEdgeDetector;
5
6
import java.io.File;
7
import java.io.IOException;
8
import java.util.HashMap;
9
import java.util.Map;
10
11
public class EdgeDetection {
12
public Map<String, Object> run(String inputImagePath) {
13
var outputs = new HashMap<String, Object>();
14
15
try {
16
var inputFile = new File(inputImagePath);
17
var image = ImageUtilities.readMBF(inputFile);
18
var processor = new CannyEdgeDetector();
19
20
image.processInplace(processor);
21
22
var outputFile = new File("output_image.jpg");
23
ImageUtilities.write(image, outputFile);
24
outputs.put("output_image", "output_image.jpg");
25
26
} catch (IOException e) {
27
System.err.println("failed to read image");
28
}
29
30
return outputs;
31
}
32
}
Copied!
As we want to package our app using Maven we need a pom.xml file containing the dependencies.
pom.xml
1
<?xml version="1.0" encoding="UTF-8"?>
2
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4
<modelVersion>4.0.0</modelVersion>
5
<groupId>com.apeer.modules</groupId>
6
<artifactId>canny-edge-detection</artifactId>
7
<version>1.0.0</version>
8
<packaging>jar</packaging>
9
<name>EdgeDetectionExample</name>
10
<properties>
11
<openimaj.version>1.3.6</openimaj.version>
12
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
13
</properties>
14
<dependencies>
15
<dependency>
16
<groupId>com.apeer</groupId>
17
<artifactId>apeer-dev-kit</artifactId>
18
<version>1.0.4</version>
19
</dependency>
20
<dependency>
21
<groupId>org.openimaj</groupId>
22
<artifactId>image-local-features</artifactId>
23
<version>${openimaj.version}</version>
24
<scope>compile</scope>
25
</dependency>
26
<dependency>
27
<groupId>org.json</groupId>
28
<artifactId>json</artifactId>
29
<version>20180813</version>
30
</dependency>
31
</dependencies>
32
33
<build>
34
<plugins>
35
<plugin>
36
<artifactId>maven-assembly-plugin</artifactId>
37
<configuration>
38
<archive>
39
<manifest>
40
<mainClass>com.apeer.modules.ApeerMain</mainClass>
41
</manifest>
42
</archive>
43
<descriptorRefs>
44
<descriptorRef>jar-with-dependencies</descriptorRef>
45
</descriptorRefs>
46
</configuration>
47
</plugin>
48
<plugin>
49
<groupId>org.apache.maven.plugins</groupId>
50
<artifactId>maven-compiler-plugin</artifactId>
51
<version>3.8.0</version>
52
<configuration>
53
<source>11</source>
54
<target>11</target>
55
</configuration>
56
</plugin>
57
</plugins>
58
</build>
59
60
<repositories>
61
<repository>
62
<id>oss-sonatype</id>
63
<name>oss-sonatype</name>
64
<url>https://oss.sonatype.org/content/repositories/releases/</url>
65
<snapshots>
66
<enabled>true</enabled>
67
</snapshots>
68
</repository>
69
</repositories>
70
</project>
Copied!
To keep the resulting Docker image as lean as possible it makes sense to use a Docker multi-stage build. This is done within the Dockerfile.
  • In the build step we assemble the jar file of our application. This is done in a maven image (containing a JDK).
  • In the result step we define the resulting image. Thus we copy the created jar file from the build step into the resulting image and define the run command. Our canny image is based on an JRE image.
Dockerfile
1
FROM maven:3-jdk-11 as builder
2
3
COPY . /usr/src/app
4
WORKDIR /usr/src/app
5
6
RUN mvn clean compile assembly:single
7
8
FROM openjdk:11-jre-slim
9
WORKDIR /usr/src/app
10
11
COPY --from=builder /usr/src/app/target/canny-edge-detection-1.0.0-jar-with-dependencies.jar .
12
CMD [ "java", "-jar", "canny-edge-detection-1.0.0-jar-with-dependencies.jar" ]
Copied!
To finish the module we need to write the module_specification.json file. In our case the module specification is easy, as we don't have that much in- and outputs.
  • Input: The image file to be processed
  • Output: The processed image file
  • UI: Nothing to do here
module_specification.json
1
{
2
"spec": {
3
"inputs": {
4
"input_image": {
5
"type:file": {}
6
}
7
},
8
"outputs": {
9
"output_image": {
10
"type:file": {}
11
}
12
}
13
},
14
"ui": {
15
"inputs": {},
16
"outputs": {}
17
}
18
}
Copied!

Testing the module

To test our module locally we need to prepare some things in advance.
  • In your module directory create an input and output directory.
  • We need to fake the WFE_INPUT_JSON environment variable content. This is easiest done via a Docker env-file. We call this file env.env.
    1
    WFE_INPUT_JSON={ "input_image": "/input/my_image.png", "WFE_output_params_file" : "wfe_result.json" }
    Copied!
  • Put the image to process into the input folder with the file name specified in the env file (my_image.png).
  • Build the Docker image. To do so run the following build command in your module directory.
    1
    docker build -t canny-module .
    Copied!
After the build is finished we're ready to test our module.
1
docker run --rm -v $(pwd)/input/:/input/ -v $(pwd)/output:/output --env-file env.env canny-module
Copied!
After this was executed you should find the processed file in the output directory along with the JSON file containing the required output.
If you want to test the produced image you can start an interactive shell in it. To do so just modify the run command to the following:
docker run -ti --rm -v $(pwd)/input/:/input/ -v $(pwd)/output:/output --env-file env.env canny-module bash

Fast lane for impatient coders ;)

Of course we have prepared the zipped project folder and some ready to run files for copy and paste:
ApeerMain.java
Java
Dockerfile
module_specification.json
pom.xml
1
package com.apeer.modules;
2
3
import com.apeer.sdk.ApeerDevKit;
4
import com.apeer.sdk.ApeerEnvironmentException;
5
import com.apeer.sdk.ApeerInputException;
6
import com.apeer.sdk.ApeerOutputException;
7
8
public class ApeerMain {
9
public static void main(String[] args) {
10
try {
11
var adk = new ApeerDevKit();
12
var inputImagePath = adk.getInput("input_image", String.class);
13
14
var outputs = new EdgeDetection().run(inputImagePath);
15
16
adk.setFileOutput("output_image", (String) outputs.get("output_image"));
17
adk.finalizeModule();
18
19
} catch (ApeerEnvironmentException | ApeerInputException | ApeerOutputException e) {
20
System.out.println(e.getMessage());
21
System.out.println(e.getStackTrace());
22
}
23
}
24
}
Copied!
1
package com.apeer.modules;
2
3
import org.openimaj.image.ImageUtilities;
4
import org.openimaj.image.processing.edges.CannyEdgeDetector;
5
6
import java.io.File;
7
import java.io.IOException;
8
import java.util.HashMap;
9
import java.util.Map;
10
11
public class EdgeDetection {
12
public Map<String, Object> run(String inputImagePath) {
13
var outputs = new HashMap<String, Object>();
14
15
try {
16
var inputFile = new File(inputImagePath);
17
var image = ImageUtilities.readMBF(inputFile);
18
var processor = new CannyEdgeDetector();
19
20
image.processInplace(processor);
21
22
var outputFile = new File("output_image.jpg");
23
ImageUtilities.write(image, outputFile);
24
outputs.put("output_image", "output_image.jpg");
25
26
} catch (IOException e) {
27
System.err.println("failed to read image");
28
}
29
30
return outputs;
31
}
32
}
Copied!
1
FROM maven:3-jdk-11 as builder
2
3
COPY . /usr/src/app
4
WORKDIR /usr/src/app
5
6
RUN mvn clean compile assembly:single
7
8
FROM openjdk:11-jre-slim
9
WORKDIR /usr/src/app
10
11
COPY --from=builder /usr/src/app/target/canny-edge-detection-1.0.0-jar-with-dependencies.jar .
12
CMD [ "java", "-jar", "canny-edge-detection-1.0.0-jar-with-dependencies.jar" ]
Copied!
1
{
2
"spec": {
3
"inputs": {
4
"input_image": {
5
"type:file": {}
6
}
7
},
8
"outputs": {
9
"output_image": {
10
"type:file": {}
11
}
12
}
13
},
14
"ui": {
15
"inputs": {},
16
"outputs": {}
17
}
18
}
Copied!
1
<?xml version="1.0" encoding="UTF-8"?>
2
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4
<modelVersion>4.0.0</modelVersion>
5
<groupId>com.apeer.modules</groupId>
6
<artifactId>canny-edge-detection</artifactId>
7
<version>1.0.0</version>
8
<packaging>jar</packaging>
9
<name>EdgeDetectionExample</name>
10
<properties>
11
<openimaj.version>1.3.6</openimaj.version>
12
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
13
</properties>
14
<dependencies>
15
<dependency>
16
<groupId>com.apeer</groupId>
17
<artifactId>apeer-dev-kit</artifactId>
18
<version>1.0.4</version>
19
</dependency>
20
<dependency>
21
<groupId>org.openimaj</groupId>
22
<artifactId>image-local-features</artifactId>
23
<version>${openimaj.version}</version>
24
<scope>compile</scope>
25
</dependency>
26
<dependency>
27
<groupId>org.json</groupId>
28
<artifactId>json</artifactId>
29
<version>20180813</version>
30
</dependency>
31
</dependencies>
32
33
<build>
34
<plugins>
35
<plugin>
36
<artifactId>maven-assembly-plugin</artifactId>
37
<configuration>
38
<archive>
39
<manifest>
40
<mainClass>com.apeer.modules.ApeerMain</mainClass>
41
</manifest>
42
</archive>
43
<descriptorRefs>
44
<descriptorRef>jar-with-dependencies</descriptorRef>
45
</descriptorRefs>
46
</configuration>
47
</plugin>
48
<plugin>
49
<groupId>org.apache.maven.plugins</groupId>
50
<artifactId>maven-compiler-plugin</artifactId>
51
<version>3.8.0</version>
52
<configuration>
53
<source>11</source>
54
<target>11</target>
55
</configuration>
56
</plugin>
57
</plugins>
58
</build>
59
60
<repositories>
61
<repository>
62
<id>oss-sonatype</id>
63
<name>oss-sonatype</name>
64
<url>https://oss.sonatype.org/content/repositories/releases/</url>
65
<snapshots>
66
<enabled>true</enabled>
67
</snapshots>
68
</repository>
69
</repositories>
70
</project>
71
Copied!
You can also download the source code by creating a new 'Java Example' Module in APEER.
Java Example.zip
4KB
Binary
Java Example Module Source Code

You couldn't find all the information you need? Contact us!

If you need help, just check out our FAQ. For any further questions please contact us at [email protected] or have a look at How-tos section in our blog or follow us on Twitter to stay up to date.
Last modified 2yr ago