Skip to content

Commit

Permalink
Merge pull request #119 from Samyssmile/feat/augmentation
Browse files Browse the repository at this point in the history
Batch Processing and Random Augmentation for EDUX Image Augmentation
  • Loading branch information
Samyssmile authored Nov 10, 2023
2 parents c880c3c + 5dbac85 commit 820c483
Show file tree
Hide file tree
Showing 20 changed files with 242 additions and 35 deletions.
30 changes: 19 additions & 11 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,29 @@ Edux supports a variety of image augmentations, which can be used to increase th

#### Code Example

```java
#### Single Image

````java
AugmentationSequence augmentationSequence=
new AugmentationBuilder()
.addAugmentation(new ResizeAugmentation(width*2,height*2,ResizeQuality.QUALITY))
.addAugmentation(new ContrastAugmentation(0.6f))
.addAugmentation(new BlurAugmentation(5))
.addAugmentation(new NoiseInjectionAugmentation(40))
.addAugmentation(new MonochromeAugmentation())
.addAugmentation(new FlippingAugmentation())
.addAugmentation(new ResizeAugmentation(250,250))
.addAugmentation(new ColorEqualizationAugmentation())
.addAugmentation(new CroppingAugmentation(0.2f))
.addAugmentation(new ElasticTransformationAugmentation(5,0.5))
.addAugmentation(new PerspectiveTransformationsAugmentation(Perspective.RIGHT_TILT))
.addAugmentation(new RandomDeleteAugmentation(5,20,20))
.build();

BufferedImage augmentedImage=augmentationSequence.applyTo(image);
````

#### Run for all images in a directory

```java
AugmentationSequence augmentationSequence=
new AugmentationBuilder()
.addAugmentation(new ResizeAugmentation(250,250))
.addAugmentation(new ColorEqualizationAugmentation())
.addAugmentation(new BlurAugmentation(25))
.addAugmentation(new RandomDeleteAugmentation(10,20,20))
.build()
.run(trainImagesDir,numberOfWorkers,outputDir);
```

### Battle Royale - Which algorithm is the best?
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.jvmargs=-Xmx8g
org.gradle.jvmargs=-Xmx32g
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@ public void readBatchOfImages() throws Exception {
+ "augmentation-benchmark-images");
reader = new AugmentationImageReader();

var imageStream = reader.readBatchOfImages(benchmarkDataDir.toString(), 100, 100);
var imageStream = reader.readImagePathsAsStream(benchmarkDataDir.toString());
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package de.edux.augmentation.core;

import java.awt.image.BufferedImage;
import java.io.IOException;

public interface AugmentationSequence {

BufferedImage applyTo(BufferedImage image);

AugmentationSequence run(String directoryPath, int numberOfWorkers, String outputPath)
throws IOException, InterruptedException;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package de.edux.augmentation.core;

import de.edux.augmentation.io.ImageProcessingManager;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.List;

/** Composite augmentation that applies a sequence of augmentations. */
Expand All @@ -19,4 +21,13 @@ public BufferedImage applyTo(BufferedImage image) {
}
return currentImage;
}

@Override
public AugmentationSequence run(String directoryPath, int numberOfWorkers, String outputPath)
throws IOException, InterruptedException {
ImageProcessingManager manager =
new ImageProcessingManager(directoryPath, numberOfWorkers, this, outputPath);
manager.processImages();
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
import java.util.stream.Stream;

public class AugmentationImageReader implements IAugmentationImageReader {
public Stream<Path> readBatchOfImages(String directoryPath, int width, int height)
throws IOException {
public Stream<Path> readImagePathsAsStream(String directoryPath) throws IOException {
return Files.walk(Paths.get(directoryPath));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,5 @@

public interface IAugmentationImageReader {

/**
* Reads an image from the given path.
*
* @return The BufferedImage read from the file.
* @throws IOException If an error occurs during reading the image.
*/
Stream<Path> readBatchOfImages(String directoryPath, int width, int height) throws IOException;
Stream<Path> readImagePathsAsStream(String directoryPath) throws IOException;
}
56 changes: 56 additions & 0 deletions lib/src/main/java/de/edux/augmentation/io/ImageConsumer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package de.edux.augmentation.io;

import de.edux.augmentation.core.AugmentationSequence;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import javax.imageio.ImageIO;

public class ImageConsumer implements Runnable {
private final BlockingQueue<ImageWithName> queue;
private final AugmentationSequence augmentationSequence;
private final String outputDirectoryPath;

public ImageConsumer(
BlockingQueue<ImageWithName> queue,
AugmentationSequence augmentationSequence,
String outputDirectoryPath) {
this.queue = queue;
this.augmentationSequence = augmentationSequence;
this.outputDirectoryPath = outputDirectoryPath;
}

@Override
public void run() {
try {
while (true) {
ImageWithName image = queue.poll(2000, TimeUnit.MILLISECONDS);
BufferedImage augmentedImage = augmentationSequence.applyTo(image.image());
processImage(augmentedImage, image.fileName());
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Consumer wurde unterbrochen.");
} catch (IOException e) {
throw new RuntimeException(e);
}
}

private void processImage(BufferedImage image, String fileName) throws IOException {
// Erstellen des Dateinamens mit Zeitstempel
File outputFile = Paths.get(outputDirectoryPath, fileName).toFile();

// Stellen Sie sicher, dass das Ausgabeverzeichnis existiert
File outputDir = outputFile.getParentFile();
if (!outputDir.exists()) {
outputDir.mkdirs();
}

// Speichern des Bildes
ImageIO.write(image, "png", outputFile);
System.out.println("Bild gespeichert: " + outputFile.getAbsolutePath());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package de.edux.augmentation.io;

import de.edux.augmentation.core.AugmentationSequence;
import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class ImageProcessingManager {
private final int numberOfConsumers;
private final String inputDirectory;
private final AugmentationSequence augmentationSequence;
private final String outputDirectory;

public ImageProcessingManager(
String inputDirectoryPath,
int numberOfConsumers,
AugmentationSequence augmentationSequence,
String outputDirectory) {
this.inputDirectory = inputDirectoryPath;
this.numberOfConsumers = numberOfConsumers;
this.augmentationSequence = augmentationSequence;
this.outputDirectory = outputDirectory;
}

public void processImages() throws InterruptedException, IOException {
BlockingQueue<ImageWithName> queue = new ArrayBlockingQueue<>(1);

Thread producerThread = new Thread(new ImageProducer(queue, inputDirectory, numberOfConsumers));
producerThread.start();

ExecutorService executorService = Executors.newFixedThreadPool(numberOfConsumers);
for (int i = 0; i < numberOfConsumers; i++) {
executorService.submit(new ImageConsumer(queue, augmentationSequence, outputDirectory));
}

producerThread.join();
executorService.shutdown();
executorService.awaitTermination(2000, TimeUnit.MILLISECONDS);
}
}
45 changes: 45 additions & 0 deletions lib/src/main/java/de/edux/augmentation/io/ImageProducer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package de.edux.augmentation.io;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.AccessDeniedException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.concurrent.BlockingQueue;
import javax.imageio.ImageIO;

public class ImageProducer implements Runnable {

private final BlockingQueue<ImageWithName> queue;
private final String directoryPathString;
private final int numberOfConsumers;
private AugmentationImageReader augmentationImageReader = new AugmentationImageReader();

public ImageProducer(
BlockingQueue<ImageWithName> queue, String directoryPathString, int numberOfConsumers)
throws IOException {
this.queue = queue;
this.directoryPathString = directoryPathString;
this.numberOfConsumers = numberOfConsumers;
}

@Override
public void run() {
try {
this.augmentationImageReader
.readImagePathsAsStream(directoryPathString)
.forEach(
path -> {
try (InputStream is = Files.newInputStream(Paths.get(path.toString()))) {
queue.put(new ImageWithName(ImageIO.read(is), path.getFileName().toString()));
} catch (AccessDeniedException ex) {
System.out.println("Access denied: " + path.toString());
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
});
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
5 changes: 5 additions & 0 deletions lib/src/main/java/de/edux/augmentation/io/ImageWithName.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package de.edux.augmentation.io;

import java.awt.image.BufferedImage;

public record ImageWithName(BufferedImage image, String fileName) {}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import de.edux.augmentation.core.AugmentationSequence;
import de.edux.augmentation.effects.geomentry.Perspective;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
Expand All @@ -21,7 +22,8 @@ public class AllAugmentations {

@Test
void shouldApplyAllAugmentations() throws InterruptedException, IOException {
var originalImage = loadTestImage("augmentation/national-park.png");
var originalImage = loadTestImage("augmentation" + File.separator + "national-park.png");

int width = originalImage.getWidth();
int height = originalImage.getHeight();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import de.edux.augmentation.core.AugmentationBuilder;
import de.edux.augmentation.core.AugmentationSequence;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
Expand All @@ -22,7 +23,7 @@ public class AugmentationEffectsTest {

@Test
void shouldApplyAugmentationSequenceOnSingleImage() throws IOException, InterruptedException {
var image = loadTestImage("augmentation/edux-original_3.png");
var image = loadTestImage("augmentation" + File.separator + "edux-original_3.png");

AugmentationSequence augmentationSequence =
new AugmentationBuilder()
Expand Down Expand Up @@ -53,7 +54,7 @@ void shouldApplyAugmentationSequenceOnSingleImage() throws IOException, Interrup

@Test
void shouldLookLikeRetroPhoto() throws IOException, InterruptedException {
var originalImage = loadTestImage("augmentation/human-realistic.png");
var originalImage = loadTestImage("augmentation" + File.separator + "human-realistic.png");
int width = originalImage.getWidth();
int height = originalImage.getHeight();

Expand Down Expand Up @@ -91,7 +92,7 @@ void shouldLookLikeRetroPhoto() throws IOException, InterruptedException {

@Test
void shouldApplyBlurAugmentation() throws IOException, InterruptedException {
var originalImage = loadTestImage("augmentation/fireworks.png");
var originalImage = loadTestImage("augmentation" + File.separator + "fireworks.png");
int width = originalImage.getWidth();
int height = originalImage.getHeight();

Expand Down Expand Up @@ -123,7 +124,7 @@ void shouldApplyBlurAugmentation() throws IOException, InterruptedException {

@Test
void shouldApplyCroppingAugmentation() throws IOException, InterruptedException {
var image = loadTestImage("augmentation/edux-original_3.png");
var image = loadTestImage("augmentation" + File.separator + "edux-original_3.png");

int width = image.getWidth();
int height = image.getHeight();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import de.edux.augmentation.core.AugmentationBuilder;
import de.edux.augmentation.core.AugmentationSequence;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
Expand All @@ -19,7 +20,7 @@ class BlurAugmentationTest {

@Test
void apply() throws IOException, InterruptedException {
var image = loadTestImage("augmentation/fireworks.png");
var image = loadTestImage("augmentation" + File.separator + "fireworks.png");
int originalWidth = image.getWidth();
int originalHeight = image.getHeight();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import de.edux.augmentation.core.AugmentationBuilder;
import de.edux.augmentation.core.AugmentationSequence;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
Expand All @@ -19,7 +20,7 @@ class ColorEqualizationAugmentationTest {

@Test
void apply() throws IOException, InterruptedException {
var image = loadTestImage("augmentation/national-park.png");
var image = loadTestImage("augmentation" + File.separator + "national-park.png");
int originalWidth = image.getWidth();
int originalHeight = image.getHeight();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import de.edux.augmentation.core.AugmentationBuilder;
import de.edux.augmentation.core.AugmentationSequence;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
Expand All @@ -19,7 +20,7 @@ public class ElasticTransformationTest {

@Test
void shouldApplyAugmentationSequenceOnSingleImage() throws IOException, InterruptedException {
var image = loadTestImage("augmentation/edux-original_3.png");
var image = loadTestImage("augmentation" + File.separator + "edux-original_3.png");

AugmentationSequence augmentationSequence =
new AugmentationBuilder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import de.edux.augmentation.core.AugmentationSequence;
import de.edux.augmentation.effects.geomentry.Perspective;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
Expand All @@ -26,7 +27,9 @@ void setUp() throws IOException {}

@Test
void shouldApplyAugmentationSequenceOnSingleImage() throws IOException, InterruptedException {
var image = AugmentationTestUtils.loadTestImage("augmentation/edux-original_3.png");
var image =
AugmentationTestUtils.loadTestImage(
"augmentation" + File.separator + "edux-original_3.png");

double cosAngle = Math.cos(Math.toRadians(30)); // 30 Grad Rotation
double sinAngle = Math.sin(Math.toRadians(30));
Expand Down
Loading

0 comments on commit 820c483

Please sign in to comment.