Skip to content

Commit

Permalink
Merge pull request #118 from Samyssmile/feat/augmentation
Browse files Browse the repository at this point in the history
Feat/augmentation
  • Loading branch information
Samyssmile authored Nov 10, 2023
2 parents 90055e0 + 791067b commit c880c3c
Show file tree
Hide file tree
Showing 30 changed files with 744 additions and 215 deletions.
45 changes: 45 additions & 0 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,51 @@ EDUX supports a variety of machine learning algorithms including:
- **Support Vector Machine:** Effective for binary classification, and can be adapted for multi-class problems.
- **RandomForest:** An ensemble method providing high accuracy through building multiple decision trees.

### Augmentations

Edux supports a variety of image augmentations, which can be used to increase the performance of your model.

### Few examples:

#### Color Equalization

<figure>
<img src="https://github.com/Samyssmile/edux/assets/6922428/01d5a67c-0a62-4884-a2cc-7b0be1ee4601" width="300" alt="Original Image">
</figure>

<figure>
<img src="https://github.com/Samyssmile/edux/assets/6922428/a3b04e8a-85c7-4bf3-8f76-9f8ce330e304" width="300" alt="Color Equalized Image">
</figure>

#### Monochrome + Noise

<figure>
<img src="https://github.com/Samyssmile/edux/assets/6922428/56c4f7a4-93dc-483c-b5da-c8a15989b313" width="300" alt="Original Image">
</figure>

<figure>
<img src="https://github.com/Samyssmile/edux/assets/6922428/25a8b2e5-0373-4781-8001-114e699fc2fe" width="300" alt="Monochrome + Noise Image">
</figure>

#### Code Example

```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 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();
```

### Battle Royale - Which algorithm is the best?

We run all algorithms on the same dataset and compare the results.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package de.edux.augmentation;
package de.edux.augmentation.core;

import java.awt.image.BufferedImage;
import java.io.IOException;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package de.edux.augmentation;
package de.edux.augmentation.core;

import de.edux.augmentation.composite.CompositeAugmentationSequence;
import java.util.ArrayList;
import java.util.List;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package de.edux.augmentation;
package de.edux.augmentation.core;

import java.awt.image.BufferedImage;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
package de.edux.augmentation.composite;
package de.edux.augmentation.core;

import de.edux.augmentation.AbstractAugmentation;
import de.edux.augmentation.AugmentationSequence;
import java.awt.image.BufferedImage;
import java.nio.file.Path;
import java.util.List;
import java.util.stream.Stream;

/** Composite augmentation that applies a sequence of augmentations. */
public class CompositeAugmentationSequence implements AugmentationSequence {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
package de.edux.augmentation.effects;

import de.edux.augmentation.AbstractAugmentation;

import de.edux.augmentation.core.AbstractAugmentation;
import java.awt.image.BufferedImage;
import java.awt.image.Kernel;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;

/** This class provides an augmentation that applies a Gaussian blur to an image. */
public class BlurAugmentation extends AbstractAugmentation {

private final float radius;

/**
* Initializes a new instance of the BlurAugmentation class with the specified blur radius.
* Initializes a new instance of the BlurAugmentation class with the specified blur radius. The
* radius determines the size of the area over which the Gaussian blur is applied. A larger radius
* results in a greater blur effect, where more distant pixels influence each other, leading to a
* smoother, more blurred image. A smaller radius restricts this effect to closer pixels,
* resulting in a less blurred image. The radius is not constrained between 0 and 1; it can take
* on any positive value, with typical values ranging from 1 for a subtle blur, up to 5 or more
* for a more significant blur effect.
*
* @param radius The radius of the Gaussian blur. Higher values result in a more pronounced blur
* effect.
* @param radius The radius of the Gaussian blur. This is not a percentage but a pixel count that
* defines the size of the kernel to be applied. The actual kernel size used in the
* convolution will be (radius * 2 + 1) to ensure that it covers both sides of the central
* pixel. Typical values range from 1 to 5 or more.
*/
public BlurAugmentation(float radius) {
if (radius < 0) {
throw new IllegalArgumentException("Radius must be greater than 0.");
}
this.radius = radius;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package de.edux.augmentation.effects;

import de.edux.augmentation.core.AbstractAugmentation;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;

/**
* This class implements an augmentation that applies color equalization to an image. It enhances
* the contrast of the image by equalizing the histogram of each color channel.
*/
public class ColorEqualizationAugmentation extends AbstractAugmentation {

/**
* Applies color equalization to the provided image.
*
* @param image The BufferedImage to be augmented.
* @return The augmented BufferedImage with equalized color channels.
*/
@Override
public BufferedImage apply(BufferedImage image) {
BufferedImage equalizedImage =
new BufferedImage(image.getWidth(), image.getHeight(), image.getType());

WritableRaster sourceRaster = image.getRaster();
WritableRaster equalizedRaster = equalizedImage.getRaster();

for (int b = 0; b < sourceRaster.getNumBands(); b++) {
equalizeHistogram(sourceRaster, equalizedRaster, b);
}

return equalizedImage;
}

private void equalizeHistogram(
WritableRaster sourceRaster, WritableRaster equalizedRaster, int band) {
int w = sourceRaster.getWidth();
int h = sourceRaster.getHeight();
int[] histogram = new int[256];
float[] cdf = new float[256];

// Calculate the histogram
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
histogram[sourceRaster.getSample(x, y, band) & 0xFF]++;
}
}

int total = w * h;
float sum = 0f;
for (int i = 0; i < histogram.length; i++) {
sum += (float) histogram[i] / total;
cdf[i] = sum;
}

for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
int value = sourceRaster.getSample(x, y, band) & 0xFF;
int newValue = Math.round(cdf[value] * 255f);
equalizedRaster.setSample(x, y, band, newValue);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package de.edux.augmentation.effects;

import de.edux.augmentation.AbstractAugmentation;
import de.edux.augmentation.core.AbstractAugmentation;
import java.awt.Color;
import java.awt.image.BufferedImage;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package de.edux.augmentation.effects;

import de.edux.augmentation.AbstractAugmentation;
import de.edux.augmentation.core.AbstractAugmentation;
import java.awt.image.BufferedImage;

/** This class provides an augmentation that crops an image based on a specified factor. */
Expand Down
Original file line number Diff line number Diff line change
@@ -1,62 +1,80 @@
package de.edux.augmentation.effects;

import de.edux.augmentation.AbstractAugmentation;
import de.edux.augmentation.core.AbstractAugmentation;
import java.awt.image.BufferedImage;
import java.util.Random;

/** This class provides an augmentation that applies elastic transformations to an image. */
/** Applies an elastic transformation to an image, simulating natural distortions. */
public class ElasticTransformationAugmentation extends AbstractAugmentation {

private final double alpha;
private final double sigma;

/**
* Initializes a new instance of the ElasticTransformationAugmentation class with specified
* parameters.
* Constructs an ElasticTransformationAugmentation instance with the given parameters.
*
* @param alpha Controls the intensity of the deformation. Start with a low value and increase it
* @param sigma Controls the smoothness of the deformation. Start with a low value and increase it
* @param alpha The intensity of the transformation. Typically between 1 and 10.
* @param sigma The elasticity coefficient. Typically between 0.1 and 0.5.
*/
public ElasticTransformationAugmentation(double alpha, double sigma) {
this.alpha = alpha;
this.sigma = sigma;
}

/**
* Applies an elastic transformation to the provided image.
* Applies the elastic transformation to the provided image.
*
* @param image The BufferedImage to which the elastic transformation will be applied.
* @return A new BufferedImage with the elastic transformation applied.
* @param image The BufferedImage to transform.
* @return A new BufferedImage object with the applied elastic transformation.
*/
@Override
public BufferedImage apply(BufferedImage image) {
int width = image.getWidth();
int height = image.getHeight();
BufferedImage transformedImage = new BufferedImage(width, height, image.getType());
BufferedImage result = new BufferedImage(width, height, image.getType());

// Generate displacement fields
Random random = new Random();
double[] dx = new double[width * height];
double[] dy = new double[width * height];
for (int i = 0; i < dx.length; i++) {
dx[i] = random.nextGaussian() * sigma;
dy[i] = random.nextGaussian() * sigma;
}
double[] dx = generateDisplacementField(width, height, sigma);
double[] dy = generateDisplacementField(width, height, sigma);

// Apply displacement fields to the image
// Apply the elastic transformation
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int newX = (int) (x + dx[y * width + x] * alpha);
int newY = (int) (y + dy[y * width + x] * alpha);
int xx = (int) (x + alpha * dx[y * width + x]);
int yy = (int) (y + alpha * dy[y * width + x]);

// Bound checking
newX = Math.min(Math.max(newX, 0), width - 1);
newY = Math.min(Math.max(newY, 0), height - 1);
// Boundary condition check
if (xx < 0) xx = 0;
if (xx >= width) xx = width - 1;
if (yy < 0) yy = 0;
if (yy >= height) yy = height - 1;

transformedImage.setRGB(x, y, image.getRGB(newX, newY));
result.setRGB(x, y, image.getRGB(xx, yy));
}
}

return transformedImage;
return result;
}

/**
* Generates a displacement field for the elastic transformation.
*
* @param width The width of the displacement field.
* @param height The height of the displacement field.
* @param sigma The elasticity coefficient for the displacement field.
* @return A displacement field represented as a double array.
*/
private double[] generateDisplacementField(int width, int height, double sigma) {
double[] field = new double[width * height];
Random random = new Random();

for (int i = 0; i < field.length; i++) {
field[i] = random.nextGaussian() * sigma;
}

// Here you might want to apply a Gaussian blur to the field
// to ensure smoothness of the displacement.

return field;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package de.edux.augmentation.effects;

import de.edux.augmentation.AbstractAugmentation;
import de.edux.augmentation.core.AbstractAugmentation;
import java.awt.image.BufferedImage;
import java.util.concurrent.ThreadLocalRandom;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package de.edux.augmentation.effects;

import de.edux.augmentation.AbstractAugmentation;
import de.edux.augmentation.core.AbstractAugmentation;
import java.awt.image.BufferedImage;

/** Applies a monochrome filter to the image, converting it to grayscale. */
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package de.edux.augmentation.effects;

import de.edux.augmentation.AbstractAugmentation;
import de.edux.augmentation.core.AbstractAugmentation;
import java.awt.image.BufferedImage;
import java.util.Random;

Expand Down
Loading

0 comments on commit c880c3c

Please sign in to comment.