package fr.unistra.pelican.algorithms.spatial;
import fr.unistra.pelican.Algorithm;
import fr.unistra.pelican.AlgorithmException;
import fr.unistra.pelican.BooleanImage;
import fr.unistra.pelican.Image;
import fr.unistra.pelican.IntegerImage;
import fr.unistra.pelican.PelicanException;
import fr.unistra.pelican.algorithms.arithmetic.Minimum;
import fr.unistra.pelican.algorithms.morphology.gray.GrayExternGradient;
import fr.unistra.pelican.algorithms.morphology.gray.GrayInternGradient;
import fr.unistra.pelican.algorithms.segmentation.SeededRegionGrowing;
import fr.unistra.pelican.algorithms.segmentation.SeededRegionGrowingBasedOnLUT;
import fr.unistra.pelican.util.Point4D;
import fr.unistra.pelican.util.lut.ThreeBandByteDistanceLUT;
import fr.unistra.pelican.util.morphology.FlatStructuringElement2D;
import fr.unistra.pelican.util.neighbourhood.Neighbourhood4D;
/**
* This class implements the contract enhancement method
* proposed by P. Soille in
* P. Soille, Constrained connectivity for the processing of very-high-resolution satellite
* images, International Journal of Remote Sensing, 2010, 31: 22, 5879 — 5893
*
* Designed for 2D images, work with video and 3D images but local extremas are bad extracted if so
*
* @author Jonathan Weber
*
*/
public class ContrastEnhancementSoille extends Algorithm {
public Image inputImage;
public Point4D[] connectivity=Neighbourhood4D.get8Neighboorhood();
public Image outputImage;
public ContrastEnhancementSoille()
{
super.inputs="inputImage";
super.options="connectivity";
super.outputs="outputImage";
}
@Override
public void launch() throws AlgorithmException
{
// Initialize data
int xDim = inputImage.getXDim();
int yDim = inputImage.getYDim();
int zDim = inputImage.getZDim();
int tDim = inputImage.getTDim();
int bDim = inputImage.getBDim();
int bandSize = xDim*yDim*zDim*tDim;
// Create Map of extremum pixels
BooleanImage extremumMap=new BooleanImage(xDim,yDim,zDim,tDim,1);
extremumMap.fill(false);
for(int b=0;b<bDim;b++)
{
Image localInput = inputImage.getImage4D(b, Image.B);
Image erosionGradient = GrayInternGradient.exec(localInput, FlatStructuringElement2D.createSquareFlatStructuringElement(3));
Image dilationGradient = GrayExternGradient.exec(localInput, FlatStructuringElement2D.createSquareFlatStructuringElement(3));
Image min = Minimum.exec(erosionGradient, dilationGradient);
for(int i=0;i<bandSize;i++)
{
if(min.getPixelByte(i)==0)
{
extremumMap.setPixelBoolean(i, true);
}
}
}
int nbLabel=extremumMap.getSum();
int[][] correspondingColor = new int[nbLabel][bDim];
IntegerImage srg= new IntegerImage(xDim,yDim,zDim,tDim,1);
int label=0;
for(int t=0;t<tDim;t++)
for(int z=0;z<zDim;z++)
for(int y=0;y<yDim;y++)
for(int x=0;x<xDim;x++)
{
if(extremumMap.getPixelXYZTBoolean(x,y,z,t))
{
for(int b=0;b<bDim;b++)
{
correspondingColor[label][b]=inputImage.getPixelXYZTBByte(x, y, z, t, b);
}
srg.setPixelXYZTInt(x,y,z,t, label++);
} else
{
srg.setPixelXYZTInt(x,y,z,t, SeededRegionGrowing.UNLABELED);
}
}
if(bDim==1)
{
srg=SeededRegionGrowing.exec(inputImage, srg, connectivity, true);
} else if(bDim==3)
{
ThreeBandByteDistanceLUT lut=ThreeBandByteDistanceLUT.getClassicalL2LUT();
srg=SeededRegionGrowingBasedOnLUT.exec(inputImage, srg, connectivity, lut,true);
} else
{
throw new PelicanException("This number of bands ("+bDim+") is not managed for now");
}
outputImage=inputImage.copyImage(false);
for(int t=0;t<tDim;t++)
for(int z=0;z<zDim;z++)
for(int y=0;y<yDim;y++)
for(int x=0;x<xDim;x++)
{
int pixelLabel=srg.getPixelXYZTInt(x, y, z, t);
for(int b=0;b<bDim;b++)
{
outputImage.setPixelXYZTBByte(x, y, z, t, b, correspondingColor[pixelLabel][b]);
}
}
}
public static <T extends Image> T exec (T inputImage)
{
return (T) new ContrastEnhancementSoille().process(inputImage);
}
}