Java program to distort image by applying Voronoi Diagram filter to it (also called stained glass filter).

TheFlyingKeyboard
TheFlyingKeyboard before applying filter.
TheFlyingKeyboard distorted with Voronoi filter. Distance Order of 2 and 50000 initial points.
TheFlyingKeyboard distorted with Voronoi filter. Distance Order of 2 and 50000 initial points.

Main.java

import javax.imageio.ImageIO;
import java.io.File;

// 2018 TheFlyingKeyboard and released under MIT License
// theflyingkeyboard.net
public class Main {
    public static void main(String[] args) {
        Voronoi voronoi = new Voronoi(2, 50000, false);

        try{
            voronoi.generate(ImageIO.read(new File("tfk.png")));
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

Point2D.java

// 2018 TheFlyingKeyboard and released under MIT License
// theflyingkeyboard.net
public class Point2D {
    private int x;
    private int y;

    public Point2D(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }
}

Voronoi.java

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.concurrent.ThreadLocalRandom;

// 2018 TheFlyingKeyboard and released under MIT License
// theflyingkeyboard.net
public class Voronoi {
    private int width;
    private int height;
    private final double distanceOrder;
    private final int numberOfPoints;
    private final Point2D[] points;
    private final int[] colors;
    private final int pointSize = 5;
    private final boolean drawPoints;
    private BufferedImage bufferedImage;

    public Voronoi(double distanceOrder, int numberOfPoints, boolean drawPoints) {
        this.distanceOrder = distanceOrder;
        this.numberOfPoints = numberOfPoints;
        this.drawPoints = drawPoints;

        points = new Point2D[numberOfPoints];
        colors = new int[numberOfPoints];
    }

    public void generate(BufferedImage bufferedImage) {
        this.bufferedImage = bufferedImage;
        this.width = bufferedImage.getWidth();
        this.height = bufferedImage.getHeight();

        for (int i = 0; i < numberOfPoints; ++i) {
            points[i] = new Point2D(ThreadLocalRandom.current().nextInt(width), ThreadLocalRandom.current().nextInt(height));
            colors[i] = bufferedImage.getRGB(points[i].getX(), points[i].getY());
        }

        generateVoronoi();

        try {
            ImageIO.write(this.bufferedImage, "png", new File("Voronoi " + width + "X" + height + " " + " distance order " + distanceOrder + " " + numberOfPoints + " points.png"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void generateVoronoi() {
        int counter = 0;
        for (int y = 0; y < height; ++y) {
            for (int x = 0; x < width; ++x) {
                System.out.println((counter / (double) (height * width)) * 100 + "%");

                bufferedImage.setRGB(x, y, colors[findClosestPoint(new Point2D(x, y))]);
                ++counter;
            }
        }

        if (drawPoints) {
            drawPoints();
        }
    }

    private void drawPoints() {
        for (int i = 0; i < numberOfPoints; ++i) {
            for (int y = -pointSize; y <= pointSize; ++y) {
                for (int x = -pointSize; x <= pointSize; ++x) {
                    if (x * x + y * y <= pointSize * pointSize + pointSize && x + points[i].getX() >= 0 &&
                            x + points[i].getX() < width && y + points[i].getY() >= 0 && y + points[i].getY() < height) {
                        bufferedImage.setRGB(x + points[i].getX(), y + points[i].getY(), 0);
                    }
                }
            }
        }
    }

    private int findClosestPoint(Point2D point) {
        int index = 0;
        double minDistance = distance(point, points[index]);
        double currentDistance;

        for (int i = 1; i < numberOfPoints; ++i) {
            currentDistance = distance(point, points[i]);

            if (currentDistance < minDistance) {
                minDistance = currentDistance;
                index = i;
            }
        }

        return index;
    }

    private double distance(Point2D pointA, Point2D pointB) {
        if (distanceOrder == 1.0d) {
            return Math.abs(pointA.getX() - pointB.getX()) + Math.abs(pointA.getY() - pointB.getY());
        }

        if (distanceOrder == 2.0d) {
            return Math.sqrt((pointA.getX() - pointB.getX()) * (pointA.getX() - pointB.getX())
                    + (pointA.getY() - pointB.getY()) * (pointA.getY() - pointB.getY()));
        }

        return Math.pow(Math.pow(Math.abs(pointA.getX() - pointB.getX()), distanceOrder) +
                Math.pow(Math.abs(pointA.getY() - pointB.getY()), distanceOrder), (1.0d / distanceOrder));
    }
}

 

Java Voronoi Diagram Of Image
Tagged on:                 

Leave a Reply

Your email address will not be published. Required fields are marked *

By continuing to use the site, you agree to the use of cookies. You can read more about it the Cookies&Privacy Policy Section Above. more information

The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this. You can read more about it the Cookies&Privacy Policy Section.

Close