content: package edu.stanford.rsl.conrad.reconstruction;
  
  
  import edu.stanford.rsl.conrad.data.numeric.Grid2D;
  import edu.stanford.rsl.conrad.reconstruction.ReconstructionFilter;
  import edu.stanford.rsl.conrad.utils.Configuration;
  import edu.stanford.rsl.conrad.utils.ImageGridBuffer;
  import ij.IJ;
  
  @Deprecated
  public abstract class SuperShortScanBackprojection extends ReconstructionFilter {
  
  	/**
  	 * 
  	 */
  	private static final long serialVersionUID = 8744415315605892588L;
  	protected double [] primaryAngles;
  	protected double SID;
  	protected double width =-1;
  	protected double height = -1;
  	protected double detectorElementSizeX;
  	protected double detectorElementSizeY;
  	private boolean closed = false;
  
  	protected ReconstructionFilter projector;
  	protected ImageGridBuffer imageBuffer;
  	protected Grid2D[] projections;
  
  
  	@Override
  	public void configure() throws Exception{
  		projectionVolume = null;
  		Configuration config = Configuration.getGlobalConfiguration();
  		SID = config.getGeometry().getSourceToDetectorDistance();
  		detectorElementSizeX = config.getGeometry().getPixelDimensionX();
  		detectorElementSizeY = config.getGeometry().getPixelDimensionY();
  		//maxProjections = config.getGeometry().getProjectionStackSize();
  		//projections = new ImageProcessor[maxProjections];
  		//ReconstructionFilter [] projectors = BufferedProjectionSink.getBackprojectors();
  		//projector = (ReconstructionFilter) UserUtil.chooseObject("Select Backprojector", "Backprojector Selection", projectors, projector);
  		projector.configure();
  		configured = true;
  	}
  
  
  	@Override
  	public String getName(){
  		return "Super Short Scan Backprojector";
  	}
  
  	@Override
  	public synchronized void process(Grid2D img, int index) throws Exception{
  		if (imageBuffer == null){
  			imageBuffer = new ImageGridBuffer();
  		}
  		imageBuffer.add(img, index);
  	}
  
  	public void close(){
  		//if (true) throw new RuntimeException("closing" + closed);
  		if (!closed) {
  			projections = imageBuffer.toArray();
  			int maxProjections = imageBuffer.size();
  			imageBuffer = null;
  			// Backproject using selected algorithm
  			for(int i=0; i < maxProjections; i++){
  				IJ.showStatus("Backprojecting");
  				IJ.showProgress(((float)i)/maxProjections);
  				try {
  					
  					projector.process(projections[i], i);
  				} catch (Exception e){
  					e.printStackTrace();
  				}
  			}
  			IJ.showProgress(1.0);
  			projector.close();
  			//projectionVolume = projector.getResult();
  			//for (int n = 1; n <=projectionVolume.getNSlices(); n++){
  			//	projectionVolume.getStack().getProcessor(n).multiply(-1.0);
  			//}
  			//projectionVolume.show();
  			closed = true;
  		}
  	}
  	
  /*
  	public void close_old() throws Exception{
  		if (!closed) {
  			projections = imageBuffer.toArray();
  			int maxProjections = imageBuffer.size();
  			imageBuffer = null;
  			// precompute weights
  			double [] uWeights = new double[projections[0].getWidth()];
  			for (int i=0; i<uWeights.length;i++){
  				double pos = (i-(uWeights.length/2)) * detectorElementSizeX;
  				uWeights[i]= ((Math.pow(pos,2) + Math.pow(SID, 2)) / SID);
  			}
  			double [][] vWeights = new double[projections[0].getWidth()][projections[0].getHeight()];
  			for (int j=0; j<vWeights[0].length;j++){
  				for (int i=0; i<vWeights.length;i++){
  					double posU = (i-(vWeights.length/2)) * detectorElementSizeX;
  					double posV = (j-(vWeights[0].length/2)) * detectorElementSizeY;
  					vWeights[i][j]= (posU * posV) / SID;
  				}
  			}
  			// perform triplet-wise derivative;
  			ImageProcessor lastProjection = projections[0].duplicate();
  			for (int i = 1; i< maxProjections-1; i++){
  				IJ.showStatus("Computing lambda derivative");
  				IJ.showProgress(((float)i)/maxProjections);
  				ImageProcessor projectionBasedDerivative = computeUVDerivative(i, uWeights, vWeights);
  				ImageProcessor lambdaDerivative = lastProjection;
  				//if (i == 15) VisualizationUtil.showImageProcessor(lambdaDerivative.duplicate());
  				//lambdaDerivative.multiply(-1.0);
  				//if (i == 15) VisualizationUtil.showImageProcessor(lambdaDerivative.duplicate());
  				ImageUtil.subtractProcessors(lambdaDerivative, projections[i]);
  				//if (i == 15) VisualizationUtil.showImageProcessor(lambdaDerivative.duplicate());
  				//lambdaDerivative.multiply(-1.0);
  				//if (i == 15) VisualizationUtil.showImageProcessor(lambdaDerivative.duplicate());
  				ImageUtil.addProcessors(lambdaDerivative, projectionBasedDerivative);
  				lastProjection = projections[i];
  				projections[i] = lambdaDerivative;
  			}
  			// we assume derivative 0 in first and last projection in lambda direction.
  			projections[0]=computeUVDerivative(0, uWeights, vWeights);
  			projections[maxProjections-1]=computeUVDerivative(maxProjections-1, uWeights, vWeights);
  			// Backproject using selected algorithm
  			for(int i=0; i < maxProjections; i++){
  				IJ.showStatus("Backprojecting");
  				IJ.showProgress(((float)i)/maxProjections);
  				projector.process(projections[i], i);
  			}
  			IJ.showProgress(1.0);
  
  			closed = true;
  		}
  	}
  
  	private ImageProcessor computeUVDerivative(int index, double [] uWeights, double [][] vWeights){
  		float [] kernel = {-1, 0, 1};
  		ImageProcessor revan = new FloatProcessor(projections[index].getWidth(), projections[index].getHeight());
  		// derivative in row direction
  		ImageProcessor uDev = projections[index].duplicate();
  		uDev.convolve(kernel, 3, 1);
  		// derivative in column direction
  		ImageProcessor vDev = projections[index].duplicate();
  		vDev.convolve(kernel, 1, 3);
  		// weight and add to result.
  		for(int i =0; i<uDev.getWidth(); i++){
  			for (int j=0; j< uDev.getHeight(); j++){
  				double u = uDev.getPixelValue(i,j);
  				u *= uWeights[i];
  				double v = vDev.getPixelValue(i, j);
  				v *= vWeights[i][j];
  				revan.putPixelValue(i, j, v+u);
  			}
  		}
  		return revan;
  	}
  */
  	@Override
  	public void prepareForSerialization(){
  		super.prepareForSerialization();
  		primaryAngles = null;
  		projections = null;
  		projector = null;
  		configured = false;
  		closed = false;
  		imageBuffer = null;
  	}
  
  	@Override
  	public String getBibtexCitation(){
  		return "see medline";
  	}
  
  	@Override
  	public String getMedlineCitation(){
  		return "Yu H, Wang G. Feldkamp-type VOI reconstruction from super-short-scan cone-beam data. Med Phys 31(6):1357-62. 2004.";
  	}
  
  }
  /*
   * Copyright (C) 2010-2014 Andreas Maier
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
  */