package edu.stanford.rsl.tutorial.fan.redundancy; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import ij.ImageJ; import ij.ImagePlus; import ij.io.Opener; import edu.stanford.rsl.conrad.data.numeric.Grid2D; import edu.stanford.rsl.conrad.data.numeric.NumericPointwiseOperators; import edu.stanford.rsl.conrad.utils.ImageUtil; import edu.stanford.rsl.tutorial.fan.CosineFilter; import edu.stanford.rsl.tutorial.fan.FanBeamBackprojector2D; import edu.stanford.rsl.tutorial.fan.FanBeamProjector2D; import edu.stanford.rsl.tutorial.fan.redundancy.SilverWeights; import edu.stanford.rsl.tutorial.filters.RamLakKernel; import edu.stanford.rsl.tutorial.phantoms.DotsGrid2D; import edu.stanford.rsl.tutorial.phantoms.MickeyMouseGrid2D; import edu.stanford.rsl.tutorial.phantoms.Phantom; import edu.stanford.rsl.tutorial.phantoms.SheppLogan; import edu.stanford.rsl.tutorial.phantoms.TestObject1; import edu.stanford.rsl.tutorial.phantoms.UniformCircleGrid2D; public class FanBeamWeightingComparison { /** * @param args */ public static void main(String[] args) { // image params int imgSzXMM = 200, // [mm] imgSzYMM = imgSzXMM; // [mm] float pxSzXMM = 1f, // [mm] pxSzYMM = pxSzXMM; // [mm] // sinogram params double fanAngle = 10.0*Math.PI/180.0, maxT = 300, // Detector length according to image dimensions to avoid truncation deltaT = 1, //gammaM = Math.atan((maxT / 2.f - 0.5) / focalLength), maxBeta = 159 * Math.PI /180.0, deltaBeta = maxBeta / 360.0; double focalLength = (maxT/2.0-0.5)/Math.tan(fanAngle); //float focalLength = 400, maxBeta = (float) Math.PI*2, deltaBeta = maxBeta / 200, maxT = 200, deltaT = 1; int phantomType = 6; // 0 = circle, 1 = MickeyMouse, 2 = TestObject1, // 3=DotsGrid // size in grid units int imgSzXGU = (int) Math.floor(imgSzXMM / pxSzXMM), // [GU] imgSzYGU = (int) Math.floor(imgSzYMM / pxSzYMM); // [GU] new ImageJ(); Opener op = new Opener(); // image object Phantom phantom; switch (phantomType) { case 0: phantom = new UniformCircleGrid2D(imgSzXGU, imgSzYGU); break; case 1: phantom = new MickeyMouseGrid2D(imgSzXGU, imgSzYGU); break; case 2: phantom = new TestObject1(imgSzXGU, imgSzYGU); break; case 3: phantom = new DotsGrid2D(imgSzXGU, imgSzYGU); break; case 4: phantom = new SheppLogan(imgSzXGU); break; case 5: // Load your own saved image here!! ImagePlus ipl = op.openZip("D:\\!Stanford\\Patent\\PaperCase\\Phantom_Paper.zip"); phantom = new DotsGrid2D(ipl.getWidth(),ipl.getHeight()); NumericPointwiseOperators.copy(phantom, ImageUtil.wrapImagePlusSlice(ipl, 0, false)); imgSzXMM = phantom.getWidth(); imgSzYMM = phantom.getHeight(); imgSzXGU = (int) Math.floor(imgSzXMM / pxSzXMM); // [GU] imgSzYGU = (int) Math.floor(imgSzYMM / pxSzYMM); // [GU] break; default: phantom = new UniformCircleGrid2D(imgSzXGU, imgSzYGU); break; } phantom.setSpacing(pxSzXMM, pxSzYMM); // origin is given in (negative) world coordinates phantom.setOrigin(-(imgSzXGU * phantom.getSpacing()[0]) / 2.0, -(imgSzYGU * phantom.getSpacing()[1]) / 2.0); phantom.show("Phantom"); Grid2D grid = phantom; // Fan Beam Projection FanBeamProjector2D fanBeamProjector = new FanBeamProjector2D(focalLength, maxBeta, deltaBeta, maxT, deltaT); Grid2D Sinogram = fanBeamProjector.projectRayDrivenCL(grid); Sinogram.show("Sinogram"); // Redundancy Weights List<Grid2D> rWeights = new ArrayList<Grid2D>(); // No weights rWeights.add( new Grid2D(Sinogram.getSize()[0], Sinogram.getSize()[1]) ); // Silver / Parkerlike weights rWeights.add(new SilverWeights(focalLength, maxT, deltaT, maxBeta, deltaBeta)); // Compensation Weights rWeights.add(new CompensationWeights(focalLength, maxT, deltaT, maxBeta, deltaBeta)); for (int i=0; i < rWeights.get(0).getSize()[0]; ++i) { for (int j=0; j < rWeights.get(0).getSize()[1]; ++j) { rWeights.get(0).setAtIndex(i, j, 1.f); } } //Show weights for (Iterator<Grid2D> it = rWeights.iterator(); it.hasNext(); ) it.next().show(); // Cosine Weights CosineFilter cosFilt = new CosineFilter(focalLength, maxT, deltaT); // Filtering RamLakKernel ramLak = new RamLakKernel((int) (maxT / deltaT), deltaT); // Backproject fan beam FanBeamBackprojector2D backprojector = new FanBeamBackprojector2D(focalLength, deltaT, deltaBeta, imgSzXMM, imgSzYMM); for (int i=0; i < rWeights.size(); ++i) { Grid2D sino = new Grid2D(Sinogram); Grid2D result = new Grid2D(FBP(sino, cosFilt, rWeights.get(i), ramLak, backprojector)); switch(i) { case 0: result.show("No Weighting"); break; case 1: result.show("Silver Weighting"); break; case 2: result.show("Compensation Weighting"); break; default: result.show("Compensation Weighting"); break; } } } private static Grid2D FBP( Grid2D Sinogram, CosineFilter cosFilt, Grid2D RedundancyWeights, RamLakKernel ramLak, FanBeamBackprojector2D backprojector) { NumericPointwiseOperators.multiplyBy(Sinogram, RedundancyWeights); for (int theta = 0; theta < Sinogram.getSize()[1]; ++theta) { cosFilt.applyToGrid(Sinogram.getSubGrid(theta)); ramLak.applyToGrid(Sinogram.getSubGrid(theta)); } return backprojector.backprojectPixelDriven(Sinogram); } } /* * Copyright (C) 2010-2014 Martin Berger * CONRAD is developed as an Open Source project under the GNU General Public License (GPL). */