package fr.unistra.pelican.algorithms.geometric;
import java.util.Arrays;
import fr.unistra.pelican.Algorithm;
import fr.unistra.pelican.Image;
/**
* This class performs a 2D image resampling on a block-based basis, it can
* either expand or reduce an image with basic processing
*
* @author Lefevre, Benjamin Perret (Fusion Rules)
*/
public class BlockResampling2D extends Algorithm {
/**
* Possible fusion rules in shrinking mode
* @author Benjamin Perret
*
*/
public static enum FusionRule {Mean,Max,Min,Median};
/**
* The input image
*/
public Image input;
/**
* The block width
*/
public int width;
/**
* The block height
*/
public int height;
/**
* A flag to determine the resampling operation: expand if true, reduce if
* false
*/
public boolean expand;
/**
* In shrinking mode, which rule is used to compute pixel value
*/
public FusionRule fusionRule=FusionRule.Mean;
/**
* The output image
*/
public Image output;
/**
* Default constructor
*/
public BlockResampling2D() {
super.inputs = "input,width,height,expand";
super.options="fusionRule";
super.outputs = "output";
}
/**
* Performs a 2D image resampling on a block-based basis
*
* @param input
* The input image
* @param width
* The block width
* @param height
* The block height
* @param expand
* A flag to determine the resampling operation: expand if true,
* reduce if false
* @return The output image
*/
@SuppressWarnings("unchecked")
public static <T extends Image> T exec(T input, int width, int height, boolean expand) {
return (T) new BlockResampling2D().process(input, width, height,
expand);
}
/**
* Performs a 2D image shrinking on a block-based basis
*
* @param input
* The input image
* @param width
* The block width
* @param height
* The block height
* @param fusionRule
* How to combine pixels in the block
* @return The output image
*/
@SuppressWarnings("unchecked")
public static <T extends Image> T exec(T input, int width, int height, FusionRule fusionRule) {
return (T) new BlockResampling2D().process(input, width, height,
false,fusionRule);
}
/*
* (non-Javadoc)
*
* @see fr.unistra.pelican.Algorithm#launch()
*/
public void launch() {
if (expand) {
output = input
.newInstance(input.getXDim() * width, input.getYDim()
* height, input.getZDim(), input.getTDim(), input
.getBDim());
output.copyAttributes(input);
for (int z = 0; z < output.getZDim(); z++)
for (int t = 0; t < output.getTDim(); t++)
for (int b = 0; b < output.getBDim(); b++)
for (int x = 0; x < output.getXDim(); x++)
for (int y = 0; y < output.getYDim(); y++)
output.setPixelDouble(x, y, z, t, b, input
.getPixelDouble(x / width, y / height,
z, t, b));
}
else {
switch(fusionRule)
{
case Mean:
processMean();
break;
case Min:
processMin();
break;
case Max:
processMax();
break;
case Median:
processMedian();
break;
}
}
}
private void processMean(){
double somme = 0;
output = input
.newInstance(input.getXDim() / width, input.getYDim()
/ height, input.getZDim(), input.getTDim(), input
.getBDim());
output.copyAttributes(input);
for (int z = 0; z < input.getZDim(); z++)
for (int t = 0; t < input.getTDim(); t++)
for (int b = 0; b < input.getBDim(); b++)
for (int x = 0; x < output.getXDim(); x++)
for (int y = 0; y < output.getYDim(); y++) {
somme = 0;
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
somme += input.getPixelDouble(x * width
+ i, y * height + j, z, t, b);
somme /= (double)(width * height);
output.setPixelDouble(x, y, z, t, b, somme);
}
}
private void processMax(){
double max;
output = input
.newInstance(input.getXDim() / width, input.getYDim()
/ height, input.getZDim(), input.getTDim(), input
.getBDim());
output.copyAttributes(input);
for (int z = 0; z < input.getZDim(); z++)
for (int t = 0; t < input.getTDim(); t++)
for (int b = 0; b < input.getBDim(); b++)
for (int x = 0; x < output.getXDim(); x++)
for (int y = 0; y < output.getYDim(); y++) {
max=Double.NEGATIVE_INFINITY;
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
{
double v=input.getPixelDouble(x * width+ i, y * height + j, z, t, b);
if(max<v)
max=v;
}
output.setPixelDouble(x, y, z, t, b, max);
}
}
private void processMin(){
double min;
output = input
.newInstance(input.getXDim() / width, input.getYDim()
/ height, input.getZDim(), input.getTDim(), input
.getBDim());
output.copyAttributes(input);
for (int z = 0; z < input.getZDim(); z++)
for (int t = 0; t < input.getTDim(); t++)
for (int b = 0; b < input.getBDim(); b++)
for (int x = 0; x < output.getXDim(); x++)
for (int y = 0; y < output.getYDim(); y++) {
min=Double.POSITIVE_INFINITY;
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
{
double v=input.getPixelDouble(x * width+ i, y * height + j, z, t, b);
if(v<min)
min=v;
}
output.setPixelDouble(x, y, z, t, b, min);
}
}
private void processMedian(){
double val[] = new double[height*width];
int pos=height*width/2;
output = input
.newInstance(input.getXDim() / width, input.getYDim()
/ height, input.getZDim(), input.getTDim(), input
.getBDim());
output.copyAttributes(input);
for (int z = 0; z < input.getZDim(); z++)
for (int t = 0; t < input.getTDim(); t++)
for (int b = 0; b < input.getBDim(); b++)
for (int x = 0; x < output.getXDim(); x++)
for (int y = 0; y < output.getYDim(); y++) {
int c=0;
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
{
double v=input.getPixelDouble(x * width+ i, y * height + j, z, t, b);
val[c++]=v;
}
Arrays.sort(val);
output.setPixelDouble(x, y, z, t, b, val[pos]);
}
}
}