package edu.stanford.rsl.conrad.reconstruction; import edu.stanford.rsl.conrad.data.numeric.Grid2D; import edu.stanford.rsl.conrad.geometry.Projection; import edu.stanford.rsl.conrad.numerics.SimpleOperators; import edu.stanford.rsl.conrad.numerics.SimpleVector; import ij.process.FloatProcessor; /** * The most simple implementation of the backprojection using no speed-up methods. The name is derived from the example given at <a href="http://www.rabbitct.com/">RabbitCT</a>. * Does not include the computation of a volume of interest. * @author akmaier * */ public class LolaBunnyBackprojector extends VOIBasedReconstructionFilter { /** * */ private static final long serialVersionUID = 4887607829631536252L; public LolaBunnyBackprojector(){ super(); useVOImap = false; } @Override public void backproject(Grid2D projection, int projectionNumber) { boolean debug = false; int count = 0; initialize(projection); FloatProcessor currentProjection = new FloatProcessor(projection.getWidth(), projection.getHeight(), projection.getBuffer(), null); // Constant part of distance weighting (D^2) + additional weighting for arbitrary scan ranges double D = getGeometry().getSourceToDetectorDistance(); currentProjection.multiply(10* D*D * 2* Math.PI * getGeometry().getPixelDimensionX() / getGeometry().getNumProjectionMatrices()); int p = projectionNumber; double[] voxel = new double [4]; voxel[3] = 1; for (int k = 0; k < maxK ; k++){ // for all slices voxel[2] = (this.getGeometry().getVoxelSpacingZ() * k) - offsetZ; for (int i=0; i < maxI; i++){ // for all lines voxel[0] = (this.getGeometry().getVoxelSpacingX() * i) - offsetX; for (int j = 0; j < maxJ; j++){ // for all voxels // compute real world coordinates in homogenious coordinates; //if (voiMap[i][j][k]){ voxel[1] = (this.getGeometry().getVoxelSpacingY() * j) - offsetY; SimpleVector point3d = new SimpleVector(voxel); //Compute coordinates in projection data. Projection Pcurr = getGeometry().getProjectionMatrix(p); SimpleVector point2d = SimpleOperators.multiply(Pcurr.computeP(), point3d); double coordX = point2d.getElement(0) / point2d.getElement(2); double coordY = point2d.getElement(1) / point2d.getElement(2); // back project double distanceWeight = point2d.getElement(2); double increment = currentProjection.getInterpolatedValue(coordX + lineOffset, coordY)/(distanceWeight*distanceWeight); if (Double.isNaN(increment)){ debug = true; if (count < 10) System.out.println("NAN Happened at i = " + i + " j = " + j + " k = " + k + " projection = " + projectionNumber + " x = " + coordX + " y = " + coordY ); increment = 1; count ++; } updateVolume(i, j, k, increment); //} } } } if (debug) { throw new RuntimeException("Encountered NaN in projection!"); } } @Override public String getMedlineCitation(){ return "Rohkohl C, Keck B, Hofmann H, Hornegger J. RabbitCT - an open platform for benchmarking 3D cone-beam reconstruction algorithms. Med Phys 2009 36(9):3940-4."; } @Override public String getToolName(){ return "Lola Bunny CPU-based Backprojector"; } } /* * Copyright (C) 2010-2014 Andreas Maier * CONRAD is developed as an Open Source project under the GNU General Public License (GPL). */