package ij.plugin.filter; import java.awt.*; import java.awt.image.*; import java.util.*; import ij.*; import ij.process.*; import ij.gui.*; import ij.measure.*; import ij.util.*; /** Calculate the so-called "capacity" fractal dimension. The algorithm is called, in fractal parlance, the "box counting" method. In the simplest terms, the routine counts the number of boxes of a given size needed to cover a one pixel wide, binary (black on white) border. The procedure is repeated for boxes that are 2 to 64 pixels wide. The output consists of two columns labeled "size" and "count". A plot is generated with the log of size on the x-axis and the log of count on the y-axis and the data is fitted with a straight line. The slope (S) of the line is the negative of the fractal dimension, i.e. D=-S. A full description of the technique can be found in T. G. Smith, Jr., G. D. Lange and W. B. Marks, Fractal Methods and Results in Cellular Morphology, which appeared in J. Neurosci. Methods, 69:1123-126, 1996. --- 12/Jun/2006 G. Landini added "set is white" option, otherwise the plugin assumes that the object is always low-dimensional (i.e. the phase with the smallest number of pixels). Now it works fine for sets with D near to 2.0 */ public class FractalBoxCounter implements PlugInFilter { static String sizes = "2,3,4,6,8,12,16,32,64"; static boolean blackBackground; int[] boxSizes; float[] boxCountSums; int maxBoxSize; int[] counts; Rectangle roi; int foreground; ImagePlus imp; public int setup(String arg, ImagePlus imp) { this.imp = imp; return DOES_8G+NO_CHANGES; } public void run(ImageProcessor ip) { GenericDialog gd = new GenericDialog("Fractal Box Counter", IJ.getInstance()); gd.addStringField("Box Sizes:", sizes, 20); gd.addCheckbox("Black Background", blackBackground); gd.showDialog(); if (gd.wasCanceled()) return; String s = gd.getNextString(); blackBackground = gd.getNextBoolean (); if (s.equals("")) return; boxSizes = s2ints(s); if (boxSizes==null || boxSizes.length<1) return; boxCountSums = new float[boxSizes.length]; sizes = s; for (int i=0; i=width) { IJ.error("No non-backround pixels found."); return false; } ip.setRoi(left, 0, 1, height); histogram = ip.getHistogram(); } while (histogram[foreground]==0); //Find top edge top = -1; do { top++; ip.setRoi(left, top, width-left, 1); histogram = ip.getHistogram(); } while (histogram[foreground]==0); //Find right edge right =width+1; do { right--; ip.setRoi(right-1, top, 1, height-top); histogram = ip.getHistogram(); } while (histogram[foreground]==0); //Find bottom edge bottom =height+1; do { bottom--; ip.setRoi(left, bottom-1, right-left, 1); histogram = ip.getHistogram(); } while (histogram[foreground]==0); roi = new Rectangle(left, top, right-left, bottom-top); return true; } int count(int size, ImageProcessor ip) { int[] histogram = new int[256]; int count; int x = roi.x; int y = roi.y; int w = (size<=roi.width)?size:roi.width; int h = (size<=roi.height)?size:roi.height; int right = roi.x+roi.width; int bottom = roi.y+roi.height; int maxCount = size*size; for (int i=1; i<=maxCount; i++) counts[i] = 0; boolean done = false; do { ip.setRoi(x, y, w, h); histogram = ip.getHistogram(); counts[histogram[foreground]]++; x+=size; if (x+size>=right) { w = right-x; if (x>=right) { w = size; x = roi.x; y += size; if (y+size>=bottom) h = bottom-y; done = y>=bottom; } } } while (!done); int boxSum = 0; int nBoxes; for (int i=1; i<=maxCount; i++) { nBoxes = counts[i]; if (nBoxes!=0) boxSum += nBoxes; } return boxSum; } double plot() { int n = boxSizes.length; float[] sizes = new float[boxSizes.length]; for (int i=0; i