Skip to content

Commit

Permalink
feat(#2):Implement Newton Fractal Generator #2
Browse files Browse the repository at this point in the history
  • Loading branch information
Samuel Abramov committed Nov 9, 2023
1 parent c05380c commit 476bd07
Show file tree
Hide file tree
Showing 10 changed files with 289 additions and 52 deletions.
9 changes: 9 additions & 0 deletions build.gradle.kts → build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ java {
targetCompatibility = JavaVersion.VERSION_17
}

jar {
manifest {
attributes(
'Main-Class': 'de.fractalitylab.FractalityLab'
)
}
}


repositories {
mavenCentral()
}
Expand Down
1 change: 1 addition & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ FractalityLab is a powerful Java-based tool for generating datasets of fractal i
![alt text](https://hc-linux.eu/edux/0b69dff9-68fd-4ff2-bea4-810a452b71cc.png)
![alt text](https://hc-linux.eu/edux/2d483ca2-3579-428e-8dcc-3034208a801c.png)
![alt text](https://hc-linux.eu/edux/9b529a2f-5e63-4dd9-939c-12a09dec41e4.png)
![alt text](https://hc-linux.eu/edux/e4c215af-3f02-4250-b1af-7d23b52dc15f.png)

### Download
You can download a dataset of 1000 images (256x256) for each class generated with FractalityLab here
Expand Down
2 changes: 1 addition & 1 deletion settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
rootProject.name = "MandelbrotGan"
rootProject.name = "FractalityLab"

5 changes: 3 additions & 2 deletions src/main/java/de/fractalitylab/FractalityLab.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ public static void main(String[] args) {
config = parseArguments(args);

ImageGenerator[] imageGenerators = {
new TricornGenerator(),
new MandelbrotGenerator(),
new JuliaGenerator(),
new BurningShipGenerator(),
new TricornGenerator(),
new SierpinskiGasketGenerator()
new SierpinskiGasketGenerator(),
new NewtonFractalGenerator(),
};

List<DataElement> allDataElements = generateAllDataElements(imageGenerators);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,38 @@

import de.fractalitylab.data.ImageWriter;
import de.fractalitylab.data.DataElement;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.awt.*;
import java.util.List;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import java.util.logging.Logger;
import java.util.stream.IntStream;

public class BurningShipGenerator implements ImageGenerator{
private static final Logger LOGGER = LogManager.getLogger(BurningShipGenerator.class);
private static final Logger LOGGER = Logger.getLogger(BurningShipGenerator.class.getName());

private final ThreadLocalRandom random = ThreadLocalRandom.current();

@Override
public List<DataElement> generateImage(int width, int height, int maxIterations, int numberOfImages) {
List<DataElement> result = new ArrayList<>();
IntStream.range(1, numberOfImages + 1).parallel().forEach(imageNumber -> {
LOGGER.info("Generating Burning Ship image " + imageNumber + "...");
BufferedImage image = generateSingleImage(width, height, maxIterations*10 );
IntStream.range(1, numberOfImages + 1).forEach(imageNumber -> {
BufferedImage image;
do {
image = generateSingleImage(width, height, maxIterations*10 );

} while (!checkBlackImage(image)); // Retry if the image is predominantly black



UUID uuid = UUID.randomUUID();
ImageWriter.writeImage("burningship", uuid.toString(), image);
result.add(new DataElement(uuid.toString(), "burningship"));
});
LOGGER.info("BurningShip generation finished.");
return result;
}

Expand Down Expand Up @@ -83,6 +89,23 @@ private BufferedImage generateSingleImage(int width, int height, int maxIteratio
return image;
}

// Add this method to your BurningShipGenerator class
private boolean checkBlackImage(BufferedImage image) {
int width = image.getWidth();
int height = image.getHeight();
int[] pixels = new int[width * height];
image.getRGB(0, 0, width, height, pixels, 0, width);

int blackPixelThreshold = (int) (width * height * 0.93);
long blackPixelCount = IntStream.of(pixels).parallel().filter(color -> color == Color.BLACK.getRGB()).count();

boolean isBlack = blackPixelCount < blackPixelThreshold;
if (!isBlack) {
LOGGER.info("Image is predominantly black. Retrying...");
}
return isBlack;
}

private double[] rotatePoint(double x, double y, double angle) {
double cosAngle = Math.cos(angle);
double sinAngle = Math.sin(angle);
Expand Down
10 changes: 5 additions & 5 deletions src/main/java/de/fractalitylab/generators/JuliaGenerator.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
package de.fractalitylab.generators;

import de.fractalitylab.FractalityLab;
import de.fractalitylab.data.ImageWriter;
import de.fractalitylab.data.DataElement;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import java.util.logging.Logger;
import java.util.stream.IntStream;

public class JuliaGenerator implements ImageGenerator {
private static final Logger LOGGER = LogManager.getLogger(JuliaGenerator.class);
private static final Logger LOGGER = Logger.getLogger(JuliaGenerator.class.getName());

ThreadLocalRandom random = ThreadLocalRandom.current();

@Override
Expand All @@ -23,19 +24,18 @@ public List<DataElement> generateImage(int width, int height, int maxIterations
IntStream.range(1, numberOfImages + 1).parallel().forEach(imageNumber -> {
BufferedImage image;
do {
LOGGER.info("Generating image " + imageNumber + "...");
image = generateSingleImage(width, height, maxIterations, imageNumber);
} while (!isImageInteresting(image, 3, 10));

UUID uuid = UUID.randomUUID();
ImageWriter.writeImage("julia", uuid.toString(), image);
result.add(new DataElement(uuid.toString(), "julia"));
});
LOGGER.info("Julia generation finished.");
return result;
}

private BufferedImage generateSingleImage(int width, int height, int maxIterations, int imageNumber) {
LOGGER.info("Generating image...");
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
ThreadLocalRandom random = ThreadLocalRandom.current();

Expand Down
68 changes: 31 additions & 37 deletions src/main/java/de/fractalitylab/generators/MandelbrotGenerator.java
Original file line number Diff line number Diff line change
@@ -1,65 +1,59 @@
package de.fractalitylab.generators;

import de.fractalitylab.data.ImageWriter;
import de.fractalitylab.data.DataElement;
import de.fractalitylab.data.ImageWriter;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.awt.image.BufferedImage;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import java.util.logging.Logger;
import java.util.stream.IntStream;

public class MandelbrotGenerator implements ImageGenerator {
private static final Logger LOGGER = Logger.getLogger(MandelbrotGenerator.class.getName());

ThreadLocalRandom random = ThreadLocalRandom.current();

@Override
public List<DataElement> generateImage(int width, int height, int maxIterations, int numberOfImages) {
List<DataElement> result = new ArrayList<>();
int iterations = maxIterations * 100;
IntStream.range(1, numberOfImages + 1).parallel().forEach(imageNumber -> {
IntStream.range(1, numberOfImages + 1).forEach(imageNumber -> {
BufferedImage image;
do {
image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
double zoom = 1000.0 + random.nextDouble() * 10000.0;
double moveX = -0.7 + random.nextDouble() * 0.7;
double moveY = random.nextDouble() * 0.7;
BufferedImage finalImage = image;
IntStream.range(0, height).parallel().forEach(y -> {
for (int x = 0; x < width; x++) {
double zx = (x - width / 2.0) / zoom + moveX;
double zy = (y - height / 2.0) / zoom + moveY;
double cX = zx;
double cY = zy;
int iter = 0;
double tmp;
while ((zx * zx + zy * zy < 4) && (iter < iterations)) {
tmp = zx * zx - zy * zy + cX;
zy = 2.0 * zx * zy + cY;
zx = tmp;
iter++;
}
int color = Color.HSBtoRGB((float) iter / iterations + (iter % 2) * 0.5f, 1, iter < iterations ? 1 : 0);
finalImage.setRGB(x, y, color);
image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
double zoom = 1000.0 + random.nextDouble() * 10000.0;
double moveX = -0.7 + random.nextDouble() * 0.7;
double moveY = random.nextDouble() * 0.7;
BufferedImage finalImage = image;
IntStream.range(0, height).parallel().forEach(y -> {
for (int x = 0; x < width; x++) {
double zx = (x - width / 2.0) / zoom + moveX;
double zy = (y - height / 2.0) / zoom + moveY;
double cX = zx;
double cY = zy;
int iter = 0;
double tmp;
while ((zx * zx + zy * zy < 4) && (iter < iterations)) {
tmp = zx * zx - zy * zy + cX;
zy = 2.0 * zx * zy + cY;
zx = tmp;
iter++;
}
});
} while (isImageAllBlack(image));
int color = Color.HSBtoRGB((float) iter / iterations + (iter % 2) * 0.5f, 1, iter < iterations ? 1 : 0);
finalImage.setRGB(x, y, color);
}
});
UUID uuid = UUID.randomUUID();
ImageWriter.writeImage("mandelbrot", uuid.toString(), image);
result.add(new DataElement(uuid.toString(), "mandelbrot"));
});

LOGGER.info("Mandelbrot generation finished.");

return result;
}

private boolean isImageAllBlack(BufferedImage image) {
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
if (image.getRGB(x, y) != Color.BLACK.getRGB()) {
return false;
}
}
}
return true;
}
}
Loading

0 comments on commit 476bd07

Please sign in to comment.