package edu.stanford.rsl.conrad.volume3d;
import ij.ImagePlus;
import ij.ImageStack;
import edu.stanford.rsl.conrad.utils.ImageUtil;
/**
* 3D-FFTable Volume based on C-code from Lars Wigstroem. This volume class is able to describe a 3D grid with uniform spacing in each spatial dimension. One sub class of this volume is CUDAVolume3D which models the same data in CUDA memory.
* The corresponding operator is then CUDAVolumeOperator. Note that instantiation should be performed using the respective VolumeOperator in order to enable compatibility to CUDA.
*
* @author akmaier
* @see edu.stanford.rsl.conrad.cuda.CUDAVolume3D
* @see edu.stanford.rsl.conrad.volume3d.VolumeOperator
*/
public class Volume3D {
public int dimensions; /* #dimensions */
public int[] size = new int [MAX_DIM]; /* #points in each dimension */
public float[] spacing = new float [MAX_DIM]; /* size of points [m, s, ..] */
public int in_dim; /* inner dimension, i.e. complex or real */
public float [] [] [] data; /* buffer holding the data */
/* points at first element */
public final static int MAX_DIM = 3;
protected final static boolean DEBUG_FLAG = true;
/**
* returns 1 if the volume is real and 2 if it is complex
* @return the internal dimension of the volume.
*/
public int getInternalDimension(){
return in_dim;
}
/**
* Creates an empty volume. Use of this constructor is generally discouraged. It may result in incompatibility with CUDA.
* @param size2 sizes in each direction
* @param dim2 physical dimension in each direction
* @param inDim internal Dimension
*/
public Volume3D(int[] size2, float[] dim2, int inDim) {
/* set attributes */
this.dimensions = 3;
for (int dim_loop=0; dim_loop<this.dimensions; dim_loop++) {
this.size[dim_loop] = size2[dim_loop];
this.spacing[dim_loop] = dim2[dim_loop];
}
this.in_dim = inDim;
/* allocate memory for data buffer */
data = new float [size[0]][size[1]][size[2]*in_dim];
}
/**
* Creates a Volume3D Object which supports 3-D filtering operations. Call of this constructor is discouraged. Use the VolumeOperator instead.
*
* @param image the ImagePlus
* @param mirror size of the area which is mirrored to reduce FFT artifacts.
* @param cuty number of pixels to be cut from the original volume along y direction
* @param uneven is set if the original volume has an uneven number of slices / projections.
*/
public Volume3D(ImagePlus image, int mirror, int cuty, boolean uneven){
dimensions = 3;
in_dim = 1;
spacing = new float [3];
spacing[2] = (float) image.getCalibration().pixelWidth;
spacing[1] = (float) image.getCalibration().pixelHeight;
spacing[0] = (float) image.getCalibration().pixelDepth;
size = new int[3];
int width = image.getWidth();
int height = image.getHeight();
int depth = image.getStackSize();
size[2]=image.getWidth()+(2*mirror);
size[1]=image.getHeight()+(2*mirror)-(2*cuty);
if (!uneven){
size[0]=image.getStackSize()+(2*mirror);
} else {
size[0]=image.getStackSize()+(2*mirror)-1;
}
data = new float[size[0]][size[1]][size[2]];
for (int h = 0; h< depth; h++){
for (int j = cuty; j< height - cuty; j++){
for (int i = 0; i< width; i++){
data[mirror + h][mirror +j-cuty][mirror +i] = ((float [])image.getStack().getPixels(h+1))[(width*j)+i];
}
for (int i = 0; i< mirror; i++){
data[mirror + h][mirror +j-cuty][i] = ((float [])image.getStack().getPixels(h+1))[(width*j)+(mirror)-i-1];
data[mirror + h][mirror +j-cuty][width + mirror + i] = ((float [])image.getStack().getPixels(h+1))[(width*j)+width-i];
}
}
for (int j = 0; j< mirror; j++){
for (int i = 0; i < size[2]; i++){
data[mirror + h][j][i] = data[mirror + h][(2*mirror)-j-1][i];
data[mirror + h][size[1]-mirror+j][i] = data[mirror+h][size[1]-(mirror)-j-1][i];
}
}
}
int offset = 0;
if (uneven) offset = 1;
for (int h=0;h< mirror; h++){
for(int j = 0; j < size[1]; j++){
for (int i = 0; i < size[2]; i++){
data[h][j][i] = data[(2*mirror)-h-1][j][i];
if (size[0]-mirror+h-offset < size[0]) {
data[size[0]-mirror+h-offset][j][i] = data[size[0]-mirror-h-1-offset][j][i];
}
}
}
}
//this.getImagePlus("Mirrored").show();
}
/**
* Creates an ImagePlus to visualize the contents of this Volume.
* @param title the title of the ImagePlus
* @return the ImagePlus
*/
public ImagePlus getImagePlus(String title){
return getImagePlus(title, 0, 0, false);
}
/**
* Method to create an ImagePlus from this Volume3D. Parameters are set to remove the mirrored boundary.
* @param title the title for the ImagePlus
* @param mirror the width of the mirrored boundary. Should match the parameters used to create the volume.
* @param cuty the number of pixels which were cut along the y axis during the creation of the volume.
* @param uneven true, if the original number of slices / projections was odd.
* @return the ImagePlus
*/
public ImagePlus getImagePlus(String title, int mirror, int cuty, boolean uneven){
ImagePlus revan = new ImagePlus();
int width = size[2]-(2*mirror);
int height = size[1]-(2*mirror)+(2*cuty);
int depth;
int offset;
if (uneven) {
depth = size[0]-(2*mirror)+1;
offset = 1;
} else {
depth = size[0]-(2*mirror);
offset = 0;
}
ImageStack stack = new ImageStack(width, height, depth);
System.out.println("Image Plus with internal Dimension: " + in_dim);
for (int h = mirror; h < size[0]-mirror+offset; h++){
float [] pixels = new float[width*height];
for (int j = mirror-cuty; j< size[1]-mirror+cuty; j++){
for (int i = mirror; i< size[2]-mirror; i++){
pixels[(j-mirror+cuty)*(width)+(i-mirror)] =
data[h][j][i*in_dim];
}
}
stack.setPixels(pixels, h-mirror+1);
}
stack.setColorModel(ImageUtil.getDefaultColorModel());
revan.setStack(title, stack);
return revan;
}
/**
* prints the dimensions of the volume to STDOUT.
*/
public void printSize(){
for (int i =0; i < dimensions; i++) {
System.out.print(size[i]+ " ");
}
System.out.println("Inner Dimension: " + in_dim);
if(DEBUG_FLAG) {
System.out.println(data.length + " " + data[0].length + " " + data[0][0].length);
}
}
/**
* Releases the memory for this volume. References to data are set to null to improve garbage collection. In the CUDA version, the memory on the card is freed.
*/
public void destroy(){
spacing = null;
size = null;
data = null;
}
}
/*
* Copyright (C) 2010-2014 Andreas Maier
* CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
*/