package edu.stanford.rsl.conrad.volume3d; import static edu.stanford.rsl.conrad.filtering.multiprojection.anisotropic.AnisotropicFilterFunction.MAX_FILTERS; import static edu.stanford.rsl.conrad.filtering.multiprojection.anisotropic.AnisotropicFilterFunction.filt_get_filt_dirs; import static edu.stanford.rsl.conrad.filtering.multiprojection.anisotropic.AnisotropicFilterFunction.filt_get_n_filters; import ij.IJ; import edu.stanford.rsl.conrad.parallel.ParallelThreadExecutor; import edu.stanford.rsl.conrad.utils.CONRAD; import edu.stanford.rsl.conrad.volume3d.operations.AddSlabScalar; import edu.stanford.rsl.conrad.volume3d.operations.AddSlabs; import edu.stanford.rsl.conrad.volume3d.operations.CopySlabData; import edu.stanford.rsl.conrad.volume3d.operations.DivideSlabs; import edu.stanford.rsl.conrad.volume3d.operations.FFTShifter; import edu.stanford.rsl.conrad.volume3d.operations.InitializeGaussian; import edu.stanford.rsl.conrad.volume3d.operations.InitializeHighPass; import edu.stanford.rsl.conrad.volume3d.operations.InitializeLowPass; import edu.stanford.rsl.conrad.volume3d.operations.InitializeSquaredCosine; import edu.stanford.rsl.conrad.volume3d.operations.InitializeSquaredCosineR; import edu.stanford.rsl.conrad.volume3d.operations.MaxOfSlab; import edu.stanford.rsl.conrad.volume3d.operations.MeanOfSlab; import edu.stanford.rsl.conrad.volume3d.operations.MinOfSlab; import edu.stanford.rsl.conrad.volume3d.operations.MinOfSlabs; import edu.stanford.rsl.conrad.volume3d.operations.MultiplySlabScalar; import edu.stanford.rsl.conrad.volume3d.operations.MultiplySlabs; import edu.stanford.rsl.conrad.volume3d.operations.ParallelVolumeOperation; import edu.stanford.rsl.conrad.volume3d.operations.SquareRootSlab; import edu.stanford.rsl.conrad.volume3d.operations.UpperLimitSlab; public class ParallelVolumeOperator extends VolumeOperator { @Override public Volume3D solveMaximumEigenvalue(Volume3D [][] structureTensor) { int dimensions = structureTensor[0][0].dimensions; MaxEigenValue [] eigenComputer = new MaxEigenValue[CONRAD.getNumberOfThreads()]; for (int i = 0; i< eigenComputer.length; i++){ eigenComputer[i] = new MaxEigenValue(dimensions); Thread thread = new Thread(eigenComputer[i]); thread.start(); } float [][][][] T = new float [eigenComputer.length][structureTensor[0][0].size[2]][Volume3D.MAX_DIM][Volume3D.MAX_DIM]; Volume3D vol; int row, col; int [] size = new int [Volume3D.MAX_DIM]; int in_dim; float [] dim = new float [Volume3D.MAX_DIM]; if (DEBUG_FLAG) fprintf("filt_solve_max_eigenvalue"); /* Get size info from first file */ size = structureTensor[0][0].size; dim = structureTensor[0][0].spacing; in_dim = structureTensor[0][0].getInternalDimension(); vol= createVolume(size, dim, in_dim); int currentEigenComputer = 0; for (int indexX=0; indexX<vol.size[0]; indexX++) { for (int indexY=0; indexY<vol.size[1]; indexY++) { for (int indexZ=0; indexZ<vol.size[2]; indexZ++) { for (row=0; row<dimensions; row++) { for (col=row; col<dimensions; col++) { T[currentEigenComputer][indexZ][row][col] = structureTensor[row][col].data[indexX][indexY][indexZ]; if (row != col) T[currentEigenComputer][indexZ][col][row] = T[currentEigenComputer][indexZ][row][col]; } } } /* solve max eigenvalue ... */ eigenComputer[currentEigenComputer].setData(indexX, indexY, size[2], T[currentEigenComputer]); currentEigenComputer = (currentEigenComputer +1) % eigenComputer.length; while (true){ if (eigenComputer[currentEigenComputer].done()) break; try { Thread.sleep(CONRAD.INVERSE_SPEEDUP); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } eigenComputer[currentEigenComputer].getData(vol.data); } } for (int i = 0; i< eigenComputer.length; i++){ while (true){ if (eigenComputer[i].done()) break; try { Thread.sleep(CONRAD.INVERSE_SPEEDUP); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } eigenComputer[i].getData(vol.data); eigenComputer[i].terminate(); } return(vol); } @Override public Volume3D createDirectionalWeights(int dimensions, int size[], float dim[], float dir[], int A, FILTER_TYPE t_filt) { Volume3D vol; float [] f_max = new float [Volume3D.MAX_DIM]; float [] f_delta = new float [Volume3D.MAX_DIM]; float r_abs; int dim_loop; if (DEBUG_FLAG) fprintf("filt_cos2 "+t_filt); vol=createVolume(size, dim, 1); /* normalize filter direction */ r_abs = 0.0f; r_abs += dir[0] * dir[0]; r_abs += dir[1] * dir[1]; r_abs += dir[2] * dir[2]; r_abs = (float) Math.sqrt(r_abs); for (dim_loop=0; dim_loop<dimensions; dim_loop++) dir[dim_loop] /= r_abs; /* calculate filter boundings */ getFrequencyBoundings(dimensions, size, dim, f_max, f_delta); InitializeSquaredCosine cos = new InitializeSquaredCosine(); cos.setfDelta(f_delta); cos.setfMax(f_max); cos.setFilterType(t_filt); cos.setExponent(A); cos.setDirection(dir); unaryParallelize(cos, vol); return(vol); } @Override public Volume3D createExponentialDirectionalHighPassFilter(int dimensions, int size[], float dim[], float dir[], int A, float B, float ri, FILTER_TYPE t_filt) { Volume3D vol; float [] f_max = new float [Volume3D.MAX_DIM]; float [] f_delta = new float [Volume3D.MAX_DIM]; float r_abs; int dim_loop; if (DEBUG_FLAG) fprintf("filt_cos2_r"+t_filt); vol=createVolume(size, dim, 1); /* normalize filter direction */ r_abs=0; for (dim_loop=0; dim_loop<dimensions; dim_loop++) r_abs += dir[dim_loop] * dir[dim_loop]; r_abs = (float) Math.sqrt(r_abs); for (dim_loop=0; dim_loop<dimensions; dim_loop++) { dir[dim_loop] /= r_abs; } /* calculate filter boudings */ getFrequencyBoundings(dimensions, size, dim, f_max, f_delta); InitializeSquaredCosineR cosR = new InitializeSquaredCosineR(); cosR.setfDelta(f_delta); cosR.setfMax(f_max); cosR.setFilterType(t_filt); cosR.setExponent(A); cosR.setDirection(dir); cosR.setB(B); cosR.setRi(ri); unaryParallelize(cosR, vol); //vol.getImagePlus(dir[0] + " " +dir[1] + " " +dir[2] +" Cosine Square R").show(); fftShift(vol); //vol.getImagePlus(dir[0] + " " +dir[1] + " " +dir[2] +"Cosine Square R shifted").show(); return(vol); } @Override public Volume3D createHighPassFilter(int dimensions, int [] size, float [] dim, int filt_loop, float lp_upper){ float [][] dir = new float[MAX_FILTERS][Volume3D.MAX_DIM]; float hp_lower = (float) (10f*Math.PI); /* was PI*10 LW 2006-01-31 */ float hp_upper = (float) (10f*Math.PI); /* was PI LW 2006-01-31 */ //float lp_upper = 1.50f; /* was 1.5 LW 2006-01-31 */ Volume3D vol=createVolume(size, dim, 1); int n_filters; float [] f_max = new float [Volume3D.MAX_DIM]; float [] f_delta = new float [Volume3D.MAX_DIM]; VolumeOperator.getFrequencyBoundings(dimensions, size, dim, f_max, f_delta); /* create HP filters */ InitializeHighPass hp = new InitializeHighPass(); hp.setfDelta(f_delta); hp.setfMax(f_max); hp.setHpLower(hp_lower); hp.setHpUpper(hp_upper); hp.setLpUpper(lp_upper); unaryParallelize(hp,vol); //Volume3D.vol_fftshift(vol); filt_get_filt_dirs(vol.dimensions, dir); n_filters = filt_get_n_filters(vol.dimensions); IJ.showStatus("Computing High Pass Filters"); IJ.showProgress((((float)(filt_loop))/n_filters)); Volume3D filt = createDirectionalWeights(vol.dimensions, vol.size, vol.spacing, dir[filt_loop] , 1, FILTER_TYPE.NORMAL); if (filt==null) { fprintf( "filt_make_enhance_filters: Out of memory\n"); return(null); } multiply(filt,vol); fftShift(filt); //filt.getImagePlus("filter"+ filt_loop).show(); return filt; } public Volume3D createLowPassFilter(int dimensions, int size[], float dim [], float lp_upper){ float [] f_max = new float [Volume3D.MAX_DIM]; float [] f_delta = new float [Volume3D.MAX_DIM]; Volume3D vol = createVolume(size, dim, 1); /* calculate filter boudings */ VolumeOperator.getFrequencyBoundings(dimensions, size, dim, f_max, f_delta); /* create LP filter */ //float lp_upper = 1.50f; /* was 1.5 LW 2006-01-31 */ InitializeLowPass lp = new InitializeLowPass(); lp.setfDelta(f_delta); lp.setfMax(f_max); lp.setLpUpper(lp_upper); unaryParallelize(lp,vol); fftShift(vol); return vol; } public Volume3D createGaussLowPassFilter(int dimensions, int size[], float dim[], float alpha) { Volume3D vol; float [] f_max = new float [Volume3D.MAX_DIM]; float [] f_delta = new float [Volume3D.MAX_DIM]; if (DEBUG_FLAG) fprintf("filt_gauss"); vol=createVolume(size, dim, 1); /* calculate filter boudings */ VolumeOperator.getFrequencyBoundings(dimensions, size, dim, f_max, f_delta); InitializeGaussian gauss = new InitializeGaussian(); gauss.setfDelta(f_delta); gauss.setfMax(f_max); gauss.setSigma(alpha); unaryParallelize(gauss, vol); fftShift(vol); return(vol); } @Override public float mean(Volume3D vol) { float m; /* defined for non-complex volumes only */ if (vol.in_dim != 1) { fprintf("parallel vol_max_pos: Invalid inner dimension\n"); return(0); } m = 0.0f; ParallelVolumeOperation [] ops = unaryParallelize(new MeanOfSlab(), vol); for (int indexX=0; indexX<ops.length; indexX++) { m += ((Float)ops[indexX].getResult()).floatValue(); } m /= vol.size[0]; m /= vol.size[1]; m /= vol.size[2]; return(m); } @Override public float max(Volume3D vol) { float m; /* defined for non-complex volumes only */ if (vol.in_dim != 1) { fprintf("parallel vol_max: Invalid dimension\n"); return(0); } m = vol.data[0][0][0]; ParallelVolumeOperation [] ops = unaryParallelize(new MaxOfSlab(), vol); for (int indexX=0; indexX<ops.length; indexX++) { float value = ((Float) ops[indexX].getResult()).floatValue(); if (value > m) m = value; } return(m); } @Override public float min(Volume3D vol) { float m; /* defined for non-complex volumes only */ if (vol.in_dim != 1) { fprintf("parallel vol_max: Invalid dimension\n"); return(0); } m = vol.data[0][0][0]; ParallelVolumeOperation [] ops = unaryParallelize(new MinOfSlab(), vol); for (int indexX=0; indexX<ops.length; indexX++) { float value = ((Float) ops[indexX].getResult()).floatValue(); if (value < m) m = value; } return(m); } @Override public int multiplyScalar(Volume3D vol, float re_sc, float im_sc ) { if (DEBUG_FLAG) fprintf("parallel vol_mult_sc"); if (im_sc!=0) { makeComplex(vol); CONRAD.gc(); } scalarParallelize( new MultiplySlabScalar(), vol, re_sc, im_sc); return(0); } @Override public void makeComplex(Volume3D vol) { if (vol.in_dim == 2) return; if (vol.in_dim != 1) { fprintf("parallel vol_make_comlex: Invalid dimension\n"); return; } Volume3D temp = new Volume3D(vol.size, vol.spacing, 2); binaryScalarParallelize(new CopySlabData(), temp, vol, 1.0f, 1.0f); vol.data = null; vol.data = temp.data; temp = null; vol.in_dim = 2; return; } @Override public int addScalar(Volume3D vol, float re_sc, float im_sc ) { if (DEBUG_FLAG) fprintf("parallel vol_add_sc"); if (im_sc != 0){ makeComplex(vol); CONRAD.gc(); } scalarParallelize(new AddSlabScalar(), vol, re_sc, im_sc); return(0); } @Override public int multiply(Volume3D vol1, Volume3D vol2) { int dim_loop; if (DEBUG_FLAG) fprintf("parallel vol_mult"); for (dim_loop=0; dim_loop<vol1.in_dim; dim_loop++) if (vol1.size[dim_loop] != vol2.size[dim_loop]) { fprintf( "vol_mult: Volumes have different sizes\n"); return(-1); } if (vol1.in_dim==2 && vol2.in_dim==1) { makeComplex(vol2); CONRAD.gc(); } if (vol1.in_dim==1 && vol2.in_dim==2){ makeComplex(vol1); CONRAD.gc(); } if (vol1.in_dim>2 || vol2.in_dim>2) { fprintf( "vol_mult: Invalid dimension\n"); return(0); } binaryParallelize(new MultiplySlabs(), vol1, vol2); return(0); } @Override public int divideByVolume(Volume3D vol1, Volume3D vol2) { int dim_loop; if (DEBUG_FLAG) fprintf("vol_div"); for (dim_loop=0; dim_loop<vol1.in_dim; dim_loop++) if (vol1.size[dim_loop] != vol2.size[dim_loop]) { fprintf( "parallel vol_div: Volumes have different sizes\n"); return(-1); } if (vol1.in_dim==2 && vol2.in_dim==1) { makeComplex(vol2); CONRAD.gc(); } if (vol1.in_dim==1 && vol2.in_dim==2) { makeComplex(vol1); CONRAD.gc(); } if (vol2.in_dim>2) { fprintf( "vol_div: Invalid dimension\n"); return(0); } binaryParallelize(new DivideSlabs(), vol1, vol2); return(0); } @Override public int addVolume(Volume3D vol1, Volume3D vol2){ return addVolume(vol1, vol2, 1.0f); } @Override public int addVolume(Volume3D vol1, Volume3D vol2, double weight) { int dim_loop; if (DEBUG_FLAG) fprintf("parallel vol_add"); for (dim_loop=0; dim_loop<vol1.in_dim; dim_loop++) if (vol1.size[dim_loop] != vol2.size[dim_loop]) { fprintf( "parallel vol_add: Volumes have different sizes\n"); return(-1); } if (vol1.in_dim==2 && vol2.in_dim==1){ makeComplex(vol2); if (DEBUG_FLAG) fprintf("Made complex volume 2"); CONRAD.gc(); } if (vol1.in_dim==1 && vol2.in_dim==2){ if(DEBUG_FLAG) { fprintf("Volume 1 Z-Dim" + vol1.data[0][0].length); } makeComplex(vol1); if (DEBUG_FLAG) fprintf("Made complex volume 1"); if(DEBUG_FLAG) { fprintf("Volume 1 Z-Dim" + vol1.data[0][0].length); } CONRAD.gc(); } if (vol2.in_dim>2 || vol1.in_dim>2) { fprintf( "parallel vol_add: Invalid dimension\n"); return(-1); } binaryScalarParallelize(new AddSlabs(), vol1, vol2, (float) weight, 0f); return(0); } @Override public int minOfTwoVolumes(Volume3D vol1, Volume3D vol2) { int dim_loop; if (DEBUG_FLAG) fprintf("parallel vol_get_min"); for (dim_loop=0; dim_loop<vol1.in_dim; dim_loop++) if (vol1.size[dim_loop] != vol2.size[dim_loop]) { fprintf( "parallel vol_get_min: Volumes have different sizes\n"); return(-1); } if (vol1.in_dim!=1 || vol2.in_dim!=1) { fprintf( "parallel vol_get_min: Invalid dimension\n"); return(-1); } binaryParallelize(new MinOfSlabs(), vol1, vol2); return(0); } @Override public int abs(Volume3D vol) { if (DEBUG_FLAG) fprintf("parallel vol_abs"); if (vol.in_dim != 1 && vol.in_dim != 2) { fprintf( "parallel vol_abs: Invalid dimension\n"); return(-1); } Volume3D temp = new Volume3D(vol.size, vol.spacing, 1); binaryScalarParallelize(new CopySlabData(), temp, vol, 0.0f, 0.0f); vol.data = null; vol.data = temp.data; vol.in_dim = 1; temp = null; return(0); } @Override public int real(Volume3D vol) { if (DEBUG_FLAG) fprintf("parallel vol_real"); if (vol.in_dim == 1) return(0); if (vol.in_dim != 2) { fprintf( "vol_real: Invalid dimension\n"); return(-1); } Volume3D temp = new Volume3D(vol.size, vol.spacing, 1); binaryScalarParallelize(new CopySlabData(), temp, vol, 1.0f, 0.0f); vol.data = null; vol.data = temp.data; vol.in_dim = 1; temp = null; return (0); } @Override public int imag(Volume3D vol) { if (DEBUG_FLAG) fprintf("parallel vol_real"); if (vol.in_dim == 1) return(0); if (vol.in_dim != 2) { fprintf( "parallel vol_real: Invalid dimension\n"); return(-1); } Volume3D temp = new Volume3D(vol.size, vol.spacing, 1); binaryScalarParallelize(new CopySlabData(), temp, vol, 0.0f, 1.0f); vol.data = null; vol.data = temp.data; vol.in_dim = 1; temp = null; return (0); } public int upperLimit(Volume3D vol, float max) { if (DEBUG_FLAG) fprintf("parallel vol_cut_upper"); if (vol.in_dim != 1) { fprintf( "parallel vol_abs: Invalid dimension\n"); return(-1); } scalarParallelize(new UpperLimitSlab(), vol, max, 0f); return(0); } @Override public int sqrt(Volume3D vol) { if (DEBUG_FLAG) fprintf("parallel vol_sqrt"); if (vol.in_dim != 1) { fprintf( "parallel vol_sqrt: Invalid dimension\n"); return(-1); } unaryParallelize(new SquareRootSlab(), vol); return(0); } @Override public int fftShift(Volume3D vol) { if (DEBUG_FLAG) fprintf("vol_fftshift"); if (vol.in_dim == 1) makeComplex(vol); unaryParallelize(new FFTShifter(), vol); return(0); } private ParallelVolumeOperation [] unaryParallelize(ParallelVolumeOperation op, Volume3D vol){ int numSegments = CONRAD.getNumberOfThreads(); int segmentSize = (int) Math.ceil(((double)vol.size[0]) / numSegments); ParallelVolumeOperation [] operations = new ParallelVolumeOperation[numSegments]; for (int indexX=0; indexX<numSegments; indexX++) { operations[indexX] = op.clone(); operations[indexX].setBeginIndexX(indexX*segmentSize); operations[indexX].setEndIndexX(Math.min((indexX+1)*segmentSize, vol.size[0])); operations[indexX].setVol(vol); } ParallelThreadExecutor exec = new ParallelThreadExecutor(operations); exec.setShowStatus(false); try { exec.execute(); } catch (InterruptedException e) { e.printStackTrace(); } exec = null; return operations; } private ParallelVolumeOperation [] scalarParallelize(ParallelVolumeOperation op, Volume3D vol, float scalar1, float scalar2){ int numSegments = CONRAD.getNumberOfThreads(); int segmentSize = (int) Math.ceil(((double)vol.size[0]) / numSegments); ParallelVolumeOperation [] operations = new ParallelVolumeOperation[numSegments]; for (int indexX=0; indexX<numSegments; indexX++) { operations[indexX] = op.clone(); operations[indexX].setBeginIndexX(indexX*segmentSize); operations[indexX].setEndIndexX(Math.min((indexX+1)*segmentSize, vol.size[0])); operations[indexX].setVol(vol); operations[indexX].setScalar1(scalar1); operations[indexX].setScalar2(scalar2); //operations[indexX].run(); } ParallelThreadExecutor exec = new ParallelThreadExecutor(operations); exec.setShowStatus(false); try { exec.execute(); } catch (InterruptedException e) { e.printStackTrace(); } exec = null; return operations; } private ParallelVolumeOperation [] binaryScalarParallelize(ParallelVolumeOperation op, Volume3D vol1, Volume3D vol2, float scalar1, float scalar2){ int numSegments = CONRAD.getNumberOfThreads(); //if (DEBUG_FLAG) System.out.println("Segments: " + numSegments); int segmentSize = (int) Math.ceil(((double)vol1.size[0]) / numSegments); //if (DEBUG_FLAG) System.out.println("Segment Size " + segmentSize + " Total Size: " + vol1.size[0]); ParallelVolumeOperation [] operations = new ParallelVolumeOperation[numSegments]; for (int indexX=0; indexX<numSegments; indexX++) { operations[indexX] = op.clone(); operations[indexX].setBeginIndexX(indexX*segmentSize); operations[indexX].setEndIndexX(Math.min((indexX+1)*segmentSize, vol1.size[0])); operations[indexX].setVol1(vol1); operations[indexX].setVol2(vol2); operations[indexX].setScalar1(scalar1); operations[indexX].setScalar2(scalar2); } ParallelThreadExecutor exec = new ParallelThreadExecutor(operations); exec.setShowStatus(false); try { exec.execute(); } catch (InterruptedException e) { e.printStackTrace(); } exec = null; return operations; } private ParallelVolumeOperation [] binaryParallelize(ParallelVolumeOperation op, Volume3D vol1, Volume3D vol2){ int numSegments = CONRAD.getNumberOfThreads(); int segmentSize = (int) Math.ceil(((double)vol1.size[0]) / numSegments); ParallelVolumeOperation [] operations = new ParallelVolumeOperation[numSegments]; for (int indexX=0; indexX<numSegments; indexX++) { operations[indexX] = op.clone(); operations[indexX].setBeginIndexX(indexX*segmentSize); operations[indexX].setEndIndexX(Math.min((indexX+1)*segmentSize, vol1.size[0])); operations[indexX].setVol1(vol1); operations[indexX].setVol2(vol2); } ParallelThreadExecutor exec = new ParallelThreadExecutor(operations); exec.setShowStatus(false); try { exec.execute(); } catch (InterruptedException e) { e.printStackTrace(); } exec = null; return operations; } } /* * Copyright (C) 2010-2014 Andreas Maier * CONRAD is developed as an Open Source project under the GNU General Public License (GPL). */