## Sunday, December 7, 2014

### Superpixel algorithm implemented in Java

This Superpixel code has been stored on my hard drive for a year. Too bad, I have only very little time for my recreational image processing programming.

But here is my interpretation for Superpixel algorithm in Java programming language. The computational process itself is iterative, but I am using the Cluster objects to make the algorithm slightly easier to understand and follow. Without objects, it could be slightly faster, I have not tried to code that kind of version myself.

Interesting things to try:
• change the proximity modifier 'm' from small to large
• change the cell size 'S' from small to large

Notes
1. The algorithm does not ensure superpixel connectivity, thus the result may have orphan pixels from 'wrong' cluster inside of other cluster.
2. This algorithm works in RGB color space, some other color space (Lab for example) could give you better end results.
3. The distance calculation can be done also using "approximated" distance without square root calculations, for performance reasons.
Image segmentation in Wikipedia: http://en.wikipedia.org/wiki/Image_segmentation
SLIC Superpixels - http://ivrg.epfl.ch/research/superpixels
jSLIC code in the GitHub - https://github.com/Borda/ij-CMP-BIA

Example images

Values used: left S=16, m=130, right S=24, m=130

Values used: left S=16, m=130, right S=24, m=130

Values used: left S=16, m=130, right S=24, m=130

Example usage
Using command line

java popscan.Superpixel "C:\java\flamingo.png" c:\java\sp_flamingo.png 16 130

Source

 package popscan; import java.awt.Color; import java.awt.image.BufferedImage; import java.io.File; import java.util.Arrays; import java.util.Vector; import javax.imageio.ImageIO; /** * @author tejopa, 2014 * @version 1 * http://popscan.blogspot.com */ public class Superpixel { // arrays to store values during process double[] distances; int[] labels; int[] reds; int[] greens; int[] blues; Cluster[] clusters; // in case of instable clusters, max number of loops int maxClusteringLoops = 50; /** * @param args */ public static void main(String[] args) { if (args.length!=4) { System.out.println("Usage: java popscan.Superpixel" + " [source image filename]" + " [destination image filename]" + " [cell width S (1-255)]" + " [proximity modifier m (1-255)"); return; } // parse arguments String src = args[0]; String dst = args[1]; double S = Integer.parseInt(args[2]); double m = Double.parseDouble(args[3]); BufferedImage img = loadImage(src); Superpixel sp = new Superpixel(); BufferedImage dstImage = sp.calculate(img,S,m); // save the resulting image saveImage(dst, dstImage); } public Superpixel() {    } public BufferedImage calculate(BufferedImage image, double S, double m) { int w = image.getWidth(); int h = image.getHeight(); BufferedImage result = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); long start = System.currentTimeMillis(); // get the image pixels int[] pixels = image.getRGB(0, 0, w, h, null, 0, w); // create and fill lookup tables distances = new double[w*h]; Arrays.fill(distances, Integer.MAX_VALUE); labels = new int[w*h]; Arrays.fill(labels, -1); // split rgb-values to own arrays reds = new int[w*h]; greens = new int[w*h]; blues = new int[w*h]; for (int y=0;y>16&0x000000FF; greens[pos] = color>> 8&0x000000FF; blues[pos]  = color>> 0&0x000000FF; } } // create clusters createClusters(image, S, m); // loop until all clusters are stable! int loops = 0; boolean pixelChangedCluster = true; while (pixelChangedCluster&&loops temp = new Vector(); int w = image.getWidth(); int h = image.getHeight(); boolean even = false; double xstart = 0; int id = 0; for (double y=S/2;y