package fr.unistra.pelican.algorithms.segmentation.qfz.gray;
import java.util.ArrayList;
import fr.unistra.pelican.Algorithm;
import fr.unistra.pelican.AlgorithmException;
import fr.unistra.pelican.Image;
import fr.unistra.pelican.IntegerImage;
import fr.unistra.pelican.algorithms.conversion.AverageChannels;
import fr.unistra.pelican.algorithms.conversion.RGBToGray;
import fr.unistra.pelican.util.Point4D;
/**
* Compute connected components of the image according to alpha connectivity defined by local range alpha.
*
* Alpha value is used in byte precision.
*
* Only deal with Gray Levels, non-gray images will be transformed. X,Y,Z,T dimensions are taken into account.
*
* Algorithm is mine and quick made, probably better implementation exists but this one is quite fast.
*
* @author Jonathan Weber
*
*/
public class GrayAlphaConnectivityCC extends Algorithm {
/**
* Image to process
*/
public Image inputImage;
/**
* alpha value for local range
*/
public int alpha;
/**
* Connectivity used to determine the flat zones
*/
public Point4D[] neighbourhood;;
/**
* Flat Zones labels
*/
public IntegerImage outputImage;
private static final int INITVALUE = -2;
private static final int INQUEUE = -1;
private ArrayList<Point4D> neighboursToExpand;
private int xDim;
private int yDim;
private int zDim;
private int tDim;
private int currentLabel;
/**
* Constructor
*
*/
public GrayAlphaConnectivityCC()
{
super();
super.inputs = "inputImage,alpha,neighbourhood";
super.outputs = "outputImage";
}
@Override
public void launch() throws AlgorithmException {
xDim = inputImage.getXDim();
yDim = inputImage.getYDim();
zDim = inputImage.getZDim();
tDim = inputImage.getTDim();
neighboursToExpand = new ArrayList<Point4D>();
outputImage= new IntegerImage(xDim,yDim,zDim,tDim,1);
outputImage.fill(INITVALUE);
// Transforming image in grey level if not
if(inputImage.getBDim()==3)
{
inputImage = RGBToGray.exec(inputImage);
}
else if(inputImage.getBDim()!=1)
{
inputImage = AverageChannels.exec(inputImage);
}
currentLabel=-1;
for(int t=tDim;--t>=0;)
for(int z=zDim;--z>=0;)
for(int y=yDim;--y>=0;)
for(int x=xDim;--x>=0;)
{
if(outputImage.getPixelXYZTInt(x, y, z, t)==INITVALUE)
{
outputImage.setPixelXYZTInt(x, y, z, t, ++currentLabel);
addUnlabelledNeighboursRespectToKValueToQueue(x, y, z, t);
while(neighboursToExpand.size()!=0)
{
expandCurrentLabelTo(neighboursToExpand.remove(0));
}
}
}
}
private final void expandCurrentLabelTo(Point4D pixel)
{
outputImage.setPixelXYZTInt(pixel.x, pixel.y, pixel.z, pixel.t, currentLabel);
addUnlabelledNeighboursRespectToKValueToQueue(pixel.x, pixel.y, pixel.z, pixel.t);
}
private final void addUnlabelledNeighboursRespectToKValueToQueue(int x, int y, int z, int t)
{
int pixelValue = inputImage.getPixelXYZTByte(x, y, z, t);
for(int i=neighbourhood.length;--i>=0;)
{
int locX = x + neighbourhood[i].x;
int locY = y + neighbourhood[i].y;
int locZ = z + neighbourhood[i].z;
int locT = t + neighbourhood[i].t;
if(locX>=0&&locY>=0&&locZ>=0&&locT>=0&&locX<xDim&&locY<yDim&&locZ<zDim&&locT<tDim)
{
if(outputImage.getPixelXYZTInt(locX, locY, locZ, locT)==INITVALUE)
{
if(Math.abs(pixelValue-inputImage.getPixelXYZTByte(locX, locY, locZ, locT))<=alpha)
{
neighboursToExpand.add(new Point4D(locX, locY, locZ, locT));
outputImage.setPixelXYZTInt(locX, locY, locZ, locT,INQUEUE);
}
}
}
}
}
public static IntegerImage exec(Image inputImage, int alpha, Point4D[] neighbourhood)
{
return (IntegerImage)new GrayAlphaConnectivityCC().process(inputImage,alpha,neighbourhood);
}
}