// mean deviation contour extraction
// Press et al., Numerical Recipes, The Art of Scientific Computing, 472-4
// argument
//     region size: the nonlinear filter calculates the mean deviation of the pixel gray levels
//                  within small regions (default:4*4)
//     contour fraction: percentage of accepted pixels (regions) that are unsurrounded at a
//                  particular threshold
package yi.iu.processor.contour;
import yi.iu.processor.BinaryProcessor;
import yi.iu.processor.contour.MeanDeviationMaker;

import java.awt.*;

public class mdContourExtractor extends BinaryProcessor
{
    int regionSize= 4;
    double contourFrac= 0.9;
    
    public void mdContourExtractor (int rs, double cf) { 
        regionSize=rs;
        contourFrac=cf;
    }
    
    public int[] getProcessed(int source[], Dimension d)
    {
        MeanDeviationMaker md= new MeanDeviationMaker(regionSize);
        int[] dev= md.getProcessed(source, d);
        int width=d.width, height=d.height;
        int[] rst= new int[width*height];
        findThreshold(dev,d,rst,0,128*regionSize*regionSize);
        return rst;
    }
    
    // img: the image to be processed
    // d:   the dimension of the image
    // rst: image to be returned
    // b:   min threshold
    // e:   max threshold
    private void findThreshold(int[] img, Dimension d, int[] rst, int b, int e)
    {
        if (b>=e-1) return;
        System.err.println("finding threshold "+b+"..."+e);
        int m=(b+e)/2;
        int width=d.width, height=d.height;
        // determine it's 1 or 0 according to threshold
        for (int i=0;i<height;i++){
            for (int j=0;j<width;j++){
                if (img[i*width+j]>m) rst[i*width+j]=1;
                else rst[i*width+j]=0;
            }
        }
        // calculate the number of unsurrounded pixels
        // method1: consider all the pixels to calculate the region fraction
        /*
        int n=0,total=(width-2)*(height-2);
        for (int i=1;i<height-1;i++) {
            for (int j=1;j<width-1;j++) {
                int num= rst[(i-1)*width+(j-1)]+rst[(i-1)*width+(j)]+rst[(i-1)*width+(j+1)]+
                         rst[(i)*width+(j-1)]+rst[(i)*width+(j+1)]+
                         rst[(i+1)*width+(j-1)]+rst[(i+1)*width+(j)]+rst[(i+1)*width+(j+1)];
                if (num<=6) n++;
            }
        }
        */
        // method2: consider only the pixels on edge to calculate the region fraction
        
        int n=0,total=0;
        for (int i=1;i<height-1;i++) {
            for (int j=1;j<width-1;j++) {
                if (rst[i*width+j]==0) continue;
                total++;
                int num= rst[(i-1)*width+(j-1)]+rst[(i-1)*width+(j)]+rst[(i-1)*width+(j+1)]+
                         rst[(i)*width+(j-1)]+rst[(i)*width+(j+1)]+
                         rst[(i+1)*width+(j-1)]+rst[(i+1)*width+(j)]+rst[(i+1)*width+(j+1)];
                if (num<=6) n++;
            }
        }
        
        if (total==0) n=total=1;
        System.err.println("unsurrounded: "+n+" outof "+total+" ,"+(double)n/total);
        if (n>total*(contourFrac+0.01))
            findThreshold(img,d,rst,b,m);
        else if (n<total*(contourFrac-0.01))
            findThreshold(img,d,rst,m,e);
    }
}