Last active
August 29, 2015 13:57
-
-
Save bholzer/9412408 to your computer and use it in GitHub Desktop.
This file contains 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 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 GridBlock(int x, int y) { | |
this.x = x; | |
this.y = y; | |
} | |
public String toString() { | |
return "("+this.x+","+this.y+") - "+this.color; | |
} | |
} |
This file contains 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> activeNodes = new ArrayList<GridBlock>(); | |
// Give the starting pixel a color and add it to the active list | |
grid[startX][startY].color = colors.remove(0); | |
activeNodes.add(grid[startX][startY]); | |
img.setRGB(startX, startY, grid[startX][startY].color.getRGB()); | |
// Iterate over active nodes until all pixels are filled | |
while (activeNodes.size() > 0) { | |
GridBlock currentNode = activeNodes.remove(0); | |
// Neighborhood to search | |
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); | |
// Accumulators for RGB values to get neighborhood average | |
int aveRedAcc = 0; | |
int aveBlueAcc = 0; | |
int aveGreenAcc = 0; | |
// Iterate through neighbors | |
List<GridBlock> neighbors = new ArrayList<GridBlock>(); | |
for (int row = rowStart; row <= rowFinish; row++) { | |
for (int col = colStart; col <= colFinish; col++) { | |
if (grid[row][col].color == null) { | |
if (random.nextInt(100) < 70) { | |
neighbors.add(grid[row][col]); | |
} | |
} else { | |
if (grid[row][col] != currentNode) { | |
aveRedAcc+=grid[row][col].color.getRed(); | |
aveBlueAcc+=grid[row][col].color.getBlue(); | |
aveGreenAcc+=grid[row][col].color.getGreen(); | |
} | |
} | |
} | |
} | |
int filledNeighborCount = neighborhoodSize(neighborhoodRadius) - neighbors.size(); | |
Color averageNeighborhoodColor; | |
if (filledNeighborCount == 0) { | |
averageNeighborhoodColor = currentNode.color; | |
} else { | |
averageNeighborhoodColor = new Color(aveRedAcc/filledNeighborCount, aveGreenAcc/filledNeighborCount, aveBlueAcc/filledNeighborCount); | |
} | |
// To iterate neighbors randomly | |
Collections.shuffle(neighbors); | |
for (GridBlock neighbor : neighbors) { | |
Color colorToApply = ColorUtilities.getClosestColorFrom(colors, averageNeighborhoodColor); | |
neighbor.color = colorToApply; | |
activeNodes.add(neighbor); | |
img.setRGB(neighbor.x, neighbor.y, neighbor.color.getRGB()); | |
colors.remove(colorToApply); | |
} | |
} | |
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