/*
* Copyright 2005, 2009 Cosmin Basca.
* e-mail: cosmin.basca@gmail.com
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* Please see COPYING for the complete licence.
*/
package robo.vision;
import java.awt.Rectangle;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.WritableRaster;
import java.util.Arrays;
import javax.media.jai.Histogram;
import javax.media.jai.ImageLayout;
import javax.media.jai.UntiledOpImage;
import robo.vision.widgets.VisionUtils;
@SuppressWarnings("unchecked")
public class AdaptiveThresholdOpImage extends UntiledOpImage
{
private int size;
private int constant;
private int method;
public AdaptiveThresholdOpImage(RenderedImage source, ImageLayout layout, Integer s, Integer c,Integer m)
{
super(source, null, layout);
this.size = s.intValue();
this.constant = c.intValue();
this.method = m.intValue();
}
protected void computeImage(Raster[] srcarr, WritableRaster dst, Rectangle destRect)
{
Raster src = srcarr[0];
switch(method)
{
case AdaptiveThresholdMethod.MEAN_THRESHOLD :
applyMean(src,dst);
break;
case AdaptiveThresholdMethod.MEDIAN_THRESHOLD :
applyMedian(src,dst);
break;
case AdaptiveThresholdMethod.MEAN_MAXMIN_THRESHOLD :
applyMeanMaxMin(src,dst);
break;
case AdaptiveThresholdMethod.MEC_THRESHOLD :
applyMEC(src,dst);
break;
case AdaptiveThresholdMethod.MCC_THRESHOLD :
applyMCC(src,dst);
break;
}
}
private void applyMEC(Raster src,WritableRaster dst)
{
int width = src.getWidth();
int height= src.getHeight();
Histogram hist = VisionUtils.createHistogram(src,null,new int[]{256,256,256});
//double entropy[] = hist.getEntropy();
//get histogram
int mec = VisionUtils.getHistogramMEC(VisionUtils.getHistogramDistributions(hist,0,width,height));
int tmpSample = 0;
for(int x = 0; x < width; x++)
{
for(int y = 0; y < height; y++)
{
tmpSample = src.getSample(x,y,0);
if(tmpSample < mec)
{
setBlack(dst,x,y);
}
else
{
setWhite(dst,x,y);
}
}
}
}
private void applyMCC(Raster src,WritableRaster dst)
{
int width = src.getWidth();
int height= src.getHeight();
Histogram hist = VisionUtils.createHistogram(src,null,new int[]{256,256,256});
//get histogram
int mcc = VisionUtils.getHistogramMCC(VisionUtils.getHistogramDistributions(hist,0,width,height));
int tmpSample = 0;
for(int x = 0; x < width; x++)
{
for(int y = 0; y < height; y++)
{
tmpSample = src.getSample(x,y,0);
if(tmpSample < mcc)
{
setBlack(dst,x,y);
}
else
{
setWhite(dst,x,y);
}
}
}
}
private void applyMean(Raster src,WritableRaster dst)
{
int width = src.getWidth();
int height= src.getHeight();
int mean = 0;
int count = 0;
int tmpSample = 0;
//Now find the sum of values in the size X size neigbourhood
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
mean = 0;
count = 0;
//Check the local neighbourhood
for(int k = 0; k < size; k++)
{
for(int l = 0; l < size; l++)
{
try
{
tmpSample = src.getSample((i-((int)(size/2))+k),(j-((int)(size/2))+l),0);
mean = mean + tmpSample;
count++;
}
catch(ArrayIndexOutOfBoundsException e) //If out of bounds then ignore pixel
{
}
}
}
//Find the mean value
mean = (int)(mean /count) - this.constant;
//Threshold below the mean
tmpSample = src.getSample(i,j,0);
if(tmpSample > mean)
{
setBlack(dst,i,j);
}
else
{
setWhite(dst,i,j);
}
}
}
}
private void applyMedian(Raster src,WritableRaster dst)
{
int width = src.getWidth();
int height = src.getHeight();
int median = 0;
int tmpSample = 0;
int [] values = new int[size*size];
int count = 0;
//Now find the values in the size X size neigbourhood
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
median = 0;
count = 0;
values = new int[size*size];
//Check the local neighbourhood
for(int k = 0; k < size; k++)
{
for(int l = 0; l < size; l++)
{
try
{
tmpSample = src.getSample((i-((int)(size/2))+k),(j-((int)(size/2))+l),0);
values[count] = tmpSample;
count++;
}
//If out of bounds then ignore pixel
catch(ArrayIndexOutOfBoundsException e)
{
}
}
}
//Find the median value
//First Sort the array
Arrays.sort(values);
//Then select the median
count = count / 2;
median = values[count] - this.constant;
//Threshold below the median
tmpSample = src.getSample(i,j,0);
if(tmpSample >= median)
{
setBlack(dst,i,j);
}
else
{
setWhite(dst,i,j);
}
}
}
}
private void applyMeanMaxMin(Raster src,WritableRaster dst)
{
int width = src.getWidth();
int height = src.getHeight();
int mean = 0;
int max, min;
//int [] values = new int[size*size];
int tmp = 0;
int tmpSample = 0;
//Now find the max and min of values in the size X size neigbourhood
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
mean = 0;
max = src.getSample(i,j,0);
min = src.getSample(i,j,0);
//Check the local neighbourhood
for(int k = 0; k < size; k++)
{
for(int l = 0; l < size; l++)
{
try
{
tmpSample = src.getSample((i-((int)(size/2))+k),(j-((int)(size/2))+l),0);
tmp = tmpSample;
if(tmp > max)
{
max = tmp;
}
if(tmp < min)
{
min = tmp;
}
}
//If out of bounds then ignore pixel
catch(ArrayIndexOutOfBoundsException e)
{
}
}
}
//Find the mean value
tmp = max + min;
tmp = tmp / 2;
mean = tmp - this.constant;
//Threshold below the mean
tmpSample = src.getSample(i,j,0);
if(tmpSample >= mean)
{
setBlack(dst,i,j);
}
else
{
setWhite(dst,i,j);
}
}
}
}
private void setWhite(WritableRaster dst,int i,int j)
{
dst.setSample(i,j,0,255);
dst.setSample(i,j,1,255);
dst.setSample(i,j,2,255);
}
private void setBlack(WritableRaster dst,int i,int j)
{
dst.setSample(i,j,0,0);
dst.setSample(i,j,1,0);
dst.setSample(i,j,2,0);
}
}