Now I’ve experimented with things, I wanted to make something that would allow me to compare different effects on the same photo, and loop through a folder of pictures looking for nice effects.
I overrode mousePressed() to change the image on click.
The big challenge here was running out of Java Heap space once I had more than one image being processed – most of the images are around 2MB each. This meant I couldn’t just read in the image 3 times and manipulate it (or not manipulate it), and even drawing the original first then manipulating it meant I had two manipulated images. I tried a few things here, starting with just increasing the heap size, to no avail. Eventually what I did was resize the image down to the size I was going to display, and creating new images of that size, and then copying the pixels over.
That resolved the issue, except when looping through the images and taking screenshots – I have no idea why this would affect things. For the most part, it worked fine though.
It’s nice to compare the effects side-by-side, see the different bits that are highlighted, depending on the effect. Sometimes it just looks like the weather is completely different. I really love the night-time photos, and the effect that makes them black and white… apart from the lights. Including in this post my favourites and those I found most interesting.
One suggestion I’ve had is to ignore pixels that are at extremes in saturation/brightness (i.e. close to black or white), but having looked at the effects on more images, I’m not convinced that is going to make things better.
Source Code
ColorHelper.java
package color; import processing.core.PApplet; import processing.core.PImage; import model.HSBColor; public class ColorHelper { public static HSBColor hsbColorFromImage(PImage img, PApplet applet, int hueRange) { img.loadPixels(); int numberOfPixels = img.pixels.length; int[] hues = new int[hueRange]; float[] saturations = new float[hueRange]; float[] brightnesses = new float[hueRange]; for (int i = 0; i < numberOfPixels; i++) { int pixel = img.pixels[i]; int hue = Math.round(applet.hue(pixel)); float saturation = applet.saturation(pixel); float brightness = applet.brightness(pixel); hues[hue]++; saturations[hue] += saturation; brightnesses[hue] += brightness; } // Find the most common hue. int hueCount = hues[0]; int hue = 0; for (int i = 1; i < hues.length; i++) { if (hues[i] > hueCount) { hueCount = hues[i]; hue = i; } } // Return the color to display. float s = saturations[hue] / hueCount; float b = brightnesses[hue] / hueCount; return new HSBColor(hue, s, b); } }
CompareAndContrastHue.java
package ui; import java.io.File; import color.ColorHelper; import model.HSBColor; import processing.core.PApplet; import processing.core.PImage; @SuppressWarnings("serial") public class CompareAndContrastHue extends PApplet { int fileIndex = 0; private String[] fileNames; private static String filePath = "../data/images/"; static final int hueRange = 320; static final int hueTolerance = 40; private static final int imageWidth = 384; private static final int imageHeight = 268; public void setup() { size(3*imageWidth, imageHeight); background(0); noLoop(); colorMode(HSB, hueRange - 1); // Read in images. File dir = new File(filePath); fileNames = dir.list(); nextFileIndex(); } public void draw() { PImage img = loadImage(filePath + fileNames[fileIndex]); img.loadPixels(); img.resize(imageWidth, imageHeight); HSBColor color = ColorHelper.hsbColorFromImage(img, this, hueRange); image(img, imageWidth, 0, imageWidth, imageHeight); // Display image only showing dominant hue. drawImage(createImage(imageWidth, imageHeight, HSB), img.pixels, color, 0, 0, imageWidth, imageHeight, false); // Display image excluding dominant hue. drawImage(createImage(imageWidth, imageHeight, HSB), img.pixels, color, 2 * imageWidth, 0, imageWidth, imageHeight, true); } public void mousePressed() { nextFileIndex(); redraw(); } private void drawImage(PImage img, int[] pixels, HSBColor color, int x, int y, int width, int height, boolean showDominantHue) { img.loadPixels(); // Manipulate photo, grayscale any pixel that isn't close to that hue. for (int i = 0; i < img.pixels.length; i++) { int pixel = pixels[i]; float hue = hue(pixel); if (hueInRange(hue, color.h, hueTolerance) == showDominantHue) { float brightness = brightness(pixel); img.pixels[i] = color(brightness); } else { img.pixels[i] = pixel; } } image(img, x, y, width, height); } private void nextFileIndex() { while (true) { fileIndex++; if (fileIndex < fileNames.length) { if (fileNames[fileIndex].toLowerCase().contains(".jpg")) { break; } } else { fileIndex = 0; } } } private static boolean hueInRange(float hueA, float hueB, int tolerance) { return Math.abs(hueA - hueB) < tolerance; } }