package edu.stanford.rsl.conrad.reconstruction;
import edu.stanford.rsl.conrad.data.numeric.Grid3D;
import edu.stanford.rsl.conrad.geometry.motion.MotionField;
import edu.stanford.rsl.conrad.geometry.motion.MotionUtil;
import edu.stanford.rsl.conrad.utils.CONRAD;
/**
* This FBP-based mathod splits the reconstruction volume into sub volumes which can be processed in parallel to speed up the reconstruction further.
* Internally motion-compensated voi reconstructors are used.
* @author akmaier
*
*/
public class MotionCompensatedSubVolumeBackprojector extends SubVolumeBackprojector {
/**
*
*/
private static final long serialVersionUID = 6027629320244326462L;
MotionField motionField;
public void setMotionField(MotionField motionField) {
this.motionField = motionField;
}
public MotionField getMotionField() {
return motionField;
}
public MotionCompensatedSubVolumeBackprojector() {
numThreads = CONRAD.getNumberOfThreads();
projectors = new VOIBasedReconstructionFilter[numThreads];
subVolumes = new Grid3D[numThreads];
for (int i = 0; i < numThreads; i++){
projectors[i] = new MotionCompensatedVOIBasedReconstructionFilter();
}
}
@Override
public String getName(){
return "Parallel Motion Compensated CPU-based Sub-volume Backprojector";
}
public void initializeProjectionVolume(){
super.initializeProjectionVolume();
motionField = MotionUtil.get4DSpline();
int reconDimensionX = getGeometry().getReconDimensionX();
int reconDimensionY = getGeometry().getReconDimensionY();
int reconDimensionZ = getGeometry().getReconDimensionZ();
double voxelSpacingX = getGeometry().getVoxelSpacingX();
double voxelSpacingY = getGeometry().getVoxelSpacingY();
double voxelSpacingZ = getGeometry().getVoxelSpacingZ();
int subVolumeReconDimensionX = (int) Math.ceil((reconDimensionX + 0.0) / numThreads);
int lastSubVolumeReconDimensionX = reconDimensionX - ((numThreads - 1) * subVolumeReconDimensionX);
for (int i = 0; i < numThreads; i++){
if (debug) {
projectors[i].setMaxI(subVolumeReconDimensionX);
projectors[i].initializeProjectionVolume();
} else {
if (i < numThreads - 1)
subVolumes[i] = new Grid3D(subVolumeReconDimensionX,reconDimensionY,reconDimensionZ);
else
subVolumes[i] = new Grid3D(lastSubVolumeReconDimensionX,reconDimensionY,reconDimensionZ);
projectors[i].setProjectionVolume(subVolumes[i]);
projectors[i].offsetX = (-getGeometry().getOriginX()) - (i * subVolumeReconDimensionX * voxelSpacingX) ;
projectors[i].offsetY = ((reconDimensionY-1) * voxelSpacingY) / 2;
projectors[i].offsetZ = ((reconDimensionZ-1) * voxelSpacingZ) / 2;
if (i < numThreads - 1) {
projectors[i].setMaxI(subVolumeReconDimensionX);
} else {
projectors[i].setMaxI(lastSubVolumeReconDimensionX);
}
projectors[i].maxK = this.maxK;
projectors[i].maxJ = this.maxJ;
projectors[i].lineOffset = lineOffset;
if(projectors[i].useVOImap && projectors[i].interestedInVolume!=null){
projectors[i].setFastVOIMode(false);
projectors[i].initializeVOIMap();
}
((MotionCompensatedVOIBasedReconstructionFilter)projectors[i]).setMotionField(motionField);
projectors[i].init = true;
}
}
volumeRewritten = false;
}
@Override
public void prepareForSerialization(){
super.prepareForSerialization();
motionField = null;
}
@Override
public String getBibtexCitation() {
return CONRAD.CONRADBibtex;
}
@Override
public String getMedlineCitation() {
return CONRAD.CONRADMedline;
}
@Override
public String getToolName(){
return "Motion-compensated Subvolume CPU-based Backprojector";
}
}
/*
* Copyright (C) 2010-2014 Andreas Maier
* CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
*/