Created
February 25, 2017 06:40
-
-
Save bholzer/efbf8bb9d8584da5c4f0856ee7285275 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.awt.Color; | |
import java.util.*; | |
public class ColorListSorter { | |
public static void quickSort(List<Color> list, int pivot, int end) { | |
if (pivot < end) { | |
int q = partition(list, pivot, end); | |
quickSort(list, pivot, q); | |
quickSort(list, q+1, end); | |
} | |
} | |
public static int partition(List<Color> list, int pivot, int r) { | |
Color color = list.get(pivot); | |
int i = pivot-1; | |
int j = r+1; | |
while (true) { | |
i++; | |
while (i < r && (list.get(i).getBlue() < color.getBlue() || list.get(i).getRed() < color.getRed())) { | |
i++; | |
} | |
j--; | |
while (j > pivot && (list.get(j).getBlue() > color.getBlue() || list.get(i).getRed() < color.getRed())) { | |
j--; | |
} | |
if (i < j) { | |
Collections.swap(list, i, j); | |
} else { | |
return j; | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.awt.Color; | |
import java.util.*; | |
public class ColorUtilities { | |
public static Color getClosestColorFrom(List<Color> colorList, Color closestTo) { | |
double shortestDistance = Double.MAX_VALUE; | |
Color closestColor = closestTo; | |
for (Color color : colorList) { | |
if (!color.equals(closestTo)) { | |
double distance = (closestTo.getRed()-color.getRed())*(closestTo.getRed()-color.getRed())+ | |
(closestTo.getGreen()-color.getGreen())*(closestTo.getGreen()-color.getGreen())+ | |
(closestTo.getBlue()-color.getBlue())*(closestTo.getBlue()-color.getBlue()); | |
if (distance < shortestDistance) { | |
shortestDistance = distance; | |
closestColor = color; | |
} | |
} | |
} | |
return closestColor; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.awt.Color; | |
public class GridBlock { | |
public int x; | |
public int y; | |
public Color color; | |
public boolean filled; | |
public boolean active; | |
public GridBlock(int x, int y) { | |
this.x = x; | |
this.y = y; | |
this.active = false; | |
} | |
public String toString() { | |
return "("+this.x+","+this.y+") - "+this.color; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.awt.image.BufferedImage; | |
import java.awt.Color; | |
import java.io.BufferedOutputStream; | |
import java.io.FileOutputStream; | |
import java.io.IOException; | |
import java.io.OutputStream; | |
import javax.imageio.ImageIO; | |
import java.util.*; | |
public class RgbGenerator { | |
public static int neighborhoodSize(int radius) { | |
if (radius == 1) return 8; | |
return neighborhoodSize(radius-1)+(radius*8); | |
} | |
public static void main(String[] args) { | |
long startTime = new Date().getTime(); | |
int height = 512; | |
int width = 512; | |
int colorPerChannel = 64; //5 bits per channel, 15 bit color-depth | |
int startX = 256; | |
int startY = 256; | |
Random random = new Random(); | |
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); | |
// Create evenly distributed Color list | |
List<Color> colors = new ArrayList<Color>(); | |
for (int r = 0; r < colorPerChannel; r++) { | |
for (int g = 0; g < colorPerChannel; g++) { | |
for (int b = 0; b < colorPerChannel; b++) { | |
Color color = new Color(r*255/(colorPerChannel-1), g*255/(colorPerChannel-1), b*255/(colorPerChannel-1)); //scale values to be [0,255] | |
colors.add(color); | |
} | |
} | |
} | |
// Create a pixel grid | |
GridBlock[][] grid = new GridBlock[width][height]; | |
for (int row = 0; row < width; row++) { | |
for (int col = 0; col < height; col++) { | |
grid[row][col] = new GridBlock(row,col); | |
} | |
} | |
// List for all pixels currently being considered | |
List<GridBlock> filledNodesWithNeighbors = new ArrayList<GridBlock>(); | |
List<GridBlock> done = new ArrayList<GridBlock>(); | |
// Give the starting pixel a color and add it to the active list | |
Color startColor = colors.remove(random.nextInt(colors.size())); | |
img.setRGB(startX, startY, startColor.getRGB()); | |
grid[startX][startY].color = startColor; | |
filledNodesWithNeighbors.add(grid[startX][startY]); | |
done.add(grid[startX][startY]); | |
int stepsToTake = 1; | |
while (colors.size() > 0) { | |
List<GridBlock> perimeterNodes = new ArrayList<GridBlock>(); | |
for (GridBlock currentNode : filledNodesWithNeighbors) { | |
int neighborhoodRadius = 1; | |
int rowStart = Math.max(currentNode.x-neighborhoodRadius, 0); | |
int rowFinish = Math.min(currentNode.x+neighborhoodRadius, width-1); | |
int colStart = Math.max(currentNode.y-neighborhoodRadius, 0); | |
int colFinish = Math.min(currentNode.y+neighborhoodRadius, height-1); | |
boolean hasEmptyNeighbor = false; | |
for (int row = rowStart; row <= rowFinish; row++) { | |
for (int col = colStart; col <= colFinish; col++) { | |
if (grid[row][col].color == null && !perimeterNodes.contains(grid[row][col]) && !done.contains(grid[row][col])) { | |
hasEmptyNeighbor = true; | |
perimeterNodes.add(grid[row][col]); | |
} | |
} | |
} | |
} | |
for (GridBlock node : perimeterNodes) { | |
node.color = ColorUtilities.getClosestColorFrom(colors, startColor); | |
colors.remove(node.color); | |
filledNodesWithNeighbors.add(node); | |
img.setRGB(node.x, node.y, node.color.getRGB()); | |
done.add(node); | |
GridBlock currentNode = node; | |
for (int i = 0; i < stepsToTake; i++) { | |
List<GridBlock> unfilledNeighbors = new ArrayList<GridBlock>(); | |
int neighborhoodRadius = 1; | |
int rowStart = Math.max(currentNode.x-neighborhoodRadius, 0); | |
int rowFinish = Math.min(currentNode.x+neighborhoodRadius, width-1); | |
int colStart = Math.max(currentNode.y-neighborhoodRadius, 0); | |
int colFinish = Math.min(currentNode.y+neighborhoodRadius, height-1); | |
for (int row = rowStart; row <= rowFinish; row++) { | |
for (int col = colStart; col <= colFinish; col++) { | |
if (grid[row][col].color == null) { | |
unfilledNeighbors.add(grid[row][col]); | |
} | |
} | |
} | |
if (unfilledNeighbors.size() > 0) { | |
currentNode = unfilledNeighbors.get(random.nextInt(unfilledNeighbors.size())); | |
currentNode.color = ColorUtilities.getClosestColorFrom(colors, startColor); | |
done.add(currentNode); | |
colors.remove(currentNode.color); | |
img.setRGB(currentNode.x, currentNode.y, currentNode.color.getRGB()); | |
filledNodesWithNeighbors.add(currentNode); | |
} else { | |
filledNodesWithNeighbors.remove(currentNode); | |
} | |
} | |
} | |
} | |
System.out.println(colors.size()); //Make sure I used all the colors | |
try (OutputStream out = new BufferedOutputStream(new FileOutputStream("images/"+new Date().getTime()+".png"))) { | |
ImageIO.write(img, "png", out); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
long endTime = new Date().getTime(); | |
long executionTime = (endTime-startTime)/1000; | |
System.out.println("Finished in "+executionTime+" seconds"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment