John F. Canny's seminal paper from 1986 titled " A computational approach to edge detection" describes a fast and efficient algorithm for extracting edge information from a 2D image. A high-level description can be found at this page, and the algorithm consists of the following main steps:

Filter out the noise

Compute image gradient, resulting in gradient strength and gradient direction for each pixel

Non-maxima supression, resulting in thin edges

Thresholding / hysteresis, resulting in significant edges

At any step, you can tweak the settings according to your needs. For example, at the second step, you can either convert the original image to grayscale and apply the gradient computation, or perform the gradient computation on each one of the color channels (red, green and blue), taking the maximum value from each one. At the last step, you usually provide two values, high threshold and low threshold. Then, you start iterating over all pixels with values above the high threshold, trying to trace a "significant" edge (with either depth-first or breadth-first search). When you can't find a neighbour with value above the low threshold, the edge ends. In addition, you can decide to remove only gradient values below the low threshold, which will result in many more edges (some of which may be "false", attributed to either image noise, subtle lighting changes or small changes in texture).

The org.jvnet.ixent.algorithms.graphics.edgedetection.EdgeDetector defines an interface for edge detection implementations. It defines two enums, one for edge fuzzyness and another for edge strength. The later defines the values for low and high thresholds, while the former defines the thresholding implementation (low only, or low and high together). The existing implementation is in org.jvnet.ixent.algorithms.graphics.edgedetection.CannyEdgeDetector . To initialize the edge detector with input image, call

/**

* Initialize with Java image object

*

* @param image

* input image

*/

public void init(BufferedImage image);

To get the edge map, call

/**

* Return edge map.

*

* @param fuzzyness

* edge fuzzyness (soft or exact)

* @param strength

* edge strength (soft - many edges, very string - few edges)

* @return 2-D array of values. The value at each pixel specifies the

* probability of an edge passing through this point

*/

public IndexBitmapObject getValueMap2D(EdgeFuzzyness fuzzyness,

EdgeStrength strength);

Here are a few screenshots (click on each one to see the full-size version). The original full-color image:

The same image in grayscale (which is created internally before running the edge detection itself):

The following four images show the results of applying Canny edge detection with the full thresholding step. From left to right, the the threshold values go from low to high - note that the number of edges decreases as the threshold values increase:

The last four images show the results of applying Canny edge detection the low thresholding step only - note that the number of edges is significantly higher than before, especially on low threshold value. From left to right, the the threshold values go from low to high - note that the number of edges decreases as the threshold values increase:

Note that it's always a tradeoff between the edge quality and the edge quantity, especially with the lower threshold values. Choose the edge softness and the edge fuzzyness settings according to the specific technique you're trying to simulate. For example, for traditional mosaic, it's better to use medium thresholds to highlight the major structural features without putting too many tiles in the resulting image (preserving the overall mosaic "feel").