package fr.unistra.pelican.util.morphology;
import fr.unistra.pelican.util.Point3D;
import fr.unistra.pelican.util.Point4D;
import fr.unistra.pelican.BooleanImage;
import fr.unistra.pelican.Image;
/**
* Utility class to create images representing structuring elements
*
* @author lefevre
*
*/
public class FlatStructuringElement3D {
/**
* Create a cross line of radius radius (plus the pixel at the cross).
*
* @param radius
* @return
*/
public static BooleanImage createCrossFlatStructuringElement(
int radius) {
BooleanImage se = new BooleanImage(
2 * radius + 1, 2 * radius + 1, 2 * radius + 1, 1,1);
se.resetCenter();
for (int i = 0; i < 2 * radius + 1; i++) {
se.setPixelXYZBoolean(i, radius, radius, true);
se.setPixelXYZBoolean(radius, i, radius, true);
se.setPixelXYZBoolean(radius, radius, i, true);
}
return se;
}
/**
* Create a temporal cross line of radius radius (plus the pixel at the cross).
*
* @param radius
* @return
*/
public static BooleanImage createTemporalCrossFlatStructuringElement(
int radius) {
BooleanImage se = new BooleanImage(
2 * radius + 1, 2 * radius + 1, 1, 2 * radius + 1,1);
se.resetCenter();
for (int i = 0; i < 2 * radius + 1; i++) {
se.setPixelXYTBoolean(i, radius, radius, true);
se.setPixelXYTBoolean(radius, i, radius, true);
se.setPixelXYTBoolean(radius, radius, i, true);
}
return se;
}
/**
* Create a strange Structuring Element forme by two cones (with square base, strange, I said !)
* with base in the middle temporal frame of the SE.
*
* @param baseWidth
* @return the strange SE
*/
public static BooleanImage createTwoTemporalConesWithBaseInMiddleFrame(int baseWidth)
{
BooleanImage se = new BooleanImage(baseWidth, baseWidth, 1, baseWidth + 1, 1);
se.resetCenter();
int xDim = se.getXDim();
int yDim = se.getYDim();
int tDim = se.getTDim();
int xCenter = se.getCenter().x;
int yCenter = se.getCenter().y;
int tCenter = se.getCenter().t;
double maxDistFromCenter = Math.sqrt(xCenter*xCenter+yCenter*yCenter);
//Base filling
for(int y=0; y<yDim; y++)
for(int x=0; x<yDim; x++)
{
se.setPixelXYTBoolean(x, y, baseWidth/2, true);
}
//Cone filling
for(int t=0;t<baseWidth/2;t++)
for(int y=0; y<yDim; y++)
for(int x=0; x<xDim; x++)
{
double distFromSESpatialCenterNormalized = Math.sqrt((x-xCenter)*(x-xCenter)+(y-yCenter)*(y-yCenter))/maxDistFromCenter;
double distTemporalFromCenterNormalized = 1-((double)tCenter-(double)t)/(double)tCenter;
if(distFromSESpatialCenterNormalized<=distTemporalFromCenterNormalized)
{
se.setPixelXYTBoolean(x, y, t, true);
se.setPixelXYTBoolean(x, y, tDim-1-t, true);
}
}
return se;
}
/**
* Create a circle of radius radius (plus the pixel at the cross).
*
* @param radius
* @return
*/
public static BooleanImage createCircleFlatStructuringElement(
int radius) {
BooleanImage se = new BooleanImage(
2 * radius + 1, 2 * radius + 1, 2 * radius + 1, 1,1);
se.resetCenter();
for (int i = 0; i < 2 * radius + 1; i++) {
for (int j = 0; j < 2 * radius + 1; j++)
for (int k = 0; k < 2 * radius + 1; k++) {
if (Math
.sqrt(Math.pow(i - radius, 2)
+ Math.pow(j - radius, 2)
+ Math.pow(k - radius, 2)) <= radius + 0.000001)
se.setPixelXYZBoolean(i, j, k, true);
}
}
return se;
}
/**
* @return The transpose of the structuring element.
*/
public static BooleanImage transpose(BooleanImage se) {
BooleanImage res = new BooleanImage(se.ydim, se.xdim, se.zdim,
se.tdim, se.bdim);
for (int k = 0; k < res.zdim; k++)
for (int j = 0; j < res.ydim; j++)
for (int i = 0; i < res.xdim; i++)
res.setPixelXYZBoolean(i, j, k,se.getPixelXYZBoolean(k,j, i));
Point4D p = se.getCenter();
res.setCenter(new Point4D(p.y, p.x, p.z, p.t));
return res;
}
/**
* Create a square of edge's length size. Center is at (size/2, size/2).
*
* @param size
* @return a square SE
*/
public static BooleanImage createSquareFlatStructuringElement(
int size) {
BooleanImage se = new BooleanImage(size, size,
size, 1,1);
se.fill(true);
return se;
}
/**
* Create a temporal structuring element for 10-connectivity
*
* @param size
* @return a square SE
*/
public static BooleanImage createTemporal10ConnectivityFlatStructuringElement()
{
BooleanImage se = new BooleanImage(3, 3, 1, 3,1);
se.fill(false);
se.resetCenter();
se.setPixelXYTBoolean(1, 1, 0, true);
se.setPixelXYTBoolean(1, 1, 2, true);
se.setPixelXYTBoolean(0, 0, 1, true);
se.setPixelXYTBoolean(0, 1, 1, true);
se.setPixelXYTBoolean(0, 2, 1, true);
se.setPixelXYTBoolean(1, 0, 1, true);
se.setPixelXYTBoolean(1, 1, 1, true);
se.setPixelXYTBoolean(1, 2, 1, true);
se.setPixelXYTBoolean(2, 0, 1, true);
se.setPixelXYTBoolean(2, 1, 1, true);
se.setPixelXYTBoolean(2, 2, 1, true);
return se;
}
public static void print(BooleanImage se) {
for (int k = 0; k < se.zdim; k++) {
for (int j = 0; j < se.ydim; j++) {
for (int i = 0; i < se.xdim; i++) {
if (se.getCenter().x == i && se.getCenter().y == j && se.getCenter().z == k) {
System.out.print("+ ");
} else if (se.getPixelXYZBoolean(i,j,k)) {
System.out.print("0 ");
} else {
System.out.print(" ");
}
}
System.out.println();
}
System.out.println("\n---");
}
}
}