package edu.stanford.rsl.tutorial.fan;
import ij.ImageJ;
import edu.stanford.rsl.conrad.data.numeric.Grid2D;
import edu.stanford.rsl.conrad.data.numeric.NumericGrid;
import edu.stanford.rsl.conrad.data.numeric.NumericPointwiseOperators;
import edu.stanford.rsl.conrad.filtering.LogPoissonNoiseFilteringTool;
import edu.stanford.rsl.tutorial.fan.FanBeamBackprojector2D;
import edu.stanford.rsl.tutorial.fan.FanBeamProjector2D;
import edu.stanford.rsl.tutorial.fan.redundancy.BinaryWeights;
import edu.stanford.rsl.tutorial.fan.redundancy.CompensationWeights;
import edu.stanford.rsl.tutorial.fan.redundancy.ParkerWeights;
import edu.stanford.rsl.tutorial.fan.redundancy.SilverWeights;
import edu.stanford.rsl.tutorial.filters.RamLakKernel;
import edu.stanford.rsl.tutorial.filters.RayByRayFiltering;
import edu.stanford.rsl.tutorial.phantoms.Ellipsoid;
import edu.stanford.rsl.tutorial.phantoms.Phantom;
public class RbRFanBeamReconstructionExample{
/**
* @param args
*/
public static void main(String[] args) {
// image params
int imgSzXMM = 256, // [mm]
imgSzYMM = imgSzXMM; // [mm]
float pxSzXMM = 1.0f, // [mm]
pxSzYMM = pxSzXMM; // [mm]
// fan beam bp parameters
double gammaM = 11.768288932020647*Math.PI/180,
maxT = 500,
deltaT = 1.0,
focalLength = (maxT/2.0-0.5)*deltaT/Math.tan(gammaM),
maxBeta = 285.95*Math.PI/180,//+gammaM*2,
deltaBeta = maxBeta / 132;
System.out.println(gammaM*180/Math.PI);
int phantomType = 4; // 0 = circle, 1 = MickeyMouse, 2 = TestObject1,
// 3=DotsGrid, 4=ellipsoid
// size in grid units
int imgSzXGU = (int) Math.floor(imgSzXMM / pxSzXMM), // [GU]
imgSzYGU = (int) Math.floor(imgSzYMM / pxSzYMM); // [GU]
new ImageJ();
FanBeamProjector2D fanBeamProjector = new FanBeamProjector2D(
focalLength, maxBeta, deltaBeta, maxT, deltaT);
Phantom phantom = new Ellipsoid(imgSzXGU, imgSzYGU);
phantom.setSpacing(pxSzXMM, pxSzYMM);
// origin is given in (negative) world coordinates
phantom.setOrigin(-(imgSzXGU * phantom.getSpacing()[0]) / 2, -(imgSzYGU * phantom.getSpacing()[1]) / 2);
//phantom.setOrigin(-50.0, -50.0);
phantom.show();
Grid2D projectionP = new Grid2D(phantom);
for (int iter =0; iter < 1; iter ++) {
// create projections
Grid2D fanBeamSinoRay = fanBeamProjector.projectRayDriven(projectionP);
fanBeamSinoRay.clone().show("Sinogram");
// because the log of 0 is -inf, we need to scale down
NumericPointwiseOperators.divideBy(fanBeamSinoRay, 40);
//apply noise
LogPoissonNoiseFilteringTool pnoise = new LogPoissonNoiseFilteringTool();
try {
fanBeamSinoRay = pnoise.applyToolToImage(fanBeamSinoRay);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// scale up again
NumericPointwiseOperators.multiplyBy(fanBeamSinoRay, 40);
fanBeamSinoRay.clone().show("SinogramNoised");
int weightType = 0;
Grid2D RedundancyWeights;
switch (weightType) {
case 0:
RedundancyWeights = new ParkerWeights(focalLength, maxT, deltaT, maxBeta, deltaBeta);
break;
case 1:
RedundancyWeights = new SilverWeights(focalLength, maxT, deltaT, maxBeta, deltaBeta);
break;
case 2:
RedundancyWeights = new CompensationWeights(focalLength, maxT, deltaT, maxBeta, deltaBeta);
break;
case 3:
RedundancyWeights = new BinaryWeights(focalLength, maxT, deltaT, maxBeta, deltaBeta);
break;
default:
RedundancyWeights = new CompensationWeights(focalLength, maxT, deltaT, maxBeta, deltaBeta);
}
RedundancyWeights.show("Current Weight");
NumericPointwiseOperators.multiplyBy(fanBeamSinoRay, RedundancyWeights);
// Filter backprojection with ramp filter only
Grid2D fanBeamSinoRayOriginal = new Grid2D(fanBeamSinoRay);
// A non filtered sinogram version
Grid2D fanBeamSinoRayNoFilter = new Grid2D(fanBeamSinoRay);
// Create 11 filters, set their parameters
RayByRayFiltering rbrF = new RayByRayFiltering((int) (maxT / deltaT), deltaT, 0.5,
0.000200, 1., 1000000, 6, 405);
// Show the filters
rbrF.showFilters();
// Apply the filters
for (int i =0; i < fanBeamSinoRay.getSize()[1] ; i ++) {
rbrF.applyToGrid(fanBeamSinoRay.getSubGrid(i));
}
fanBeamSinoRay.show("After Filtering Ray by Ray");
// Do the backprojection
FanBeamBackprojector2D fbp = new FanBeamBackprojector2D(focalLength,
deltaT, deltaBeta, imgSzXMM, imgSzYMM);
Grid2D reco = fbp.backprojectPixelDriven(fanBeamSinoRay);
reco.show("Reco Ray by Ray" + iter);
NumericGrid recoDiff = NumericPointwiseOperators.subtractedBy(phantom, reco);
recoDiff.show("RecoDiff Ray by Ray" + iter);
////////////////////////
// Ramp filter only
FanBeamBackprojector2D fbp2 = new FanBeamBackprojector2D(focalLength,
deltaT, deltaBeta, imgSzXMM, imgSzYMM);
RamLakKernel ramLak2 = new RamLakKernel((int) (maxT / deltaT), deltaT);
for (int theta = 0; theta < fanBeamSinoRayOriginal.getSize()[1]; ++theta) {
ramLak2.applyToGrid(fanBeamSinoRayOriginal.getSubGrid(theta));
}
fanBeamSinoRayOriginal.show("After Filtering Ramp Only");
Grid2D reco2 = fbp2.backprojectPixelDriven(fanBeamSinoRayOriginal);
reco2.show("Reco Ramp Only" + iter);
NumericGrid recoDiff2 = NumericPointwiseOperators.subtractedBy(phantom, reco2);
recoDiff2.show("RecoDiff Ramp Only" + iter);
////////////////////////
// No filters
FanBeamBackprojector2D fbp3 = new FanBeamBackprojector2D(focalLength,
deltaT, deltaBeta, imgSzXMM, imgSzYMM);
Grid2D reco3 = fbp3.backprojectPixelDriven(fanBeamSinoRayNoFilter);
reco3.show("Reco NoFilter" + iter);
NumericGrid recoDiff3 = NumericPointwiseOperators.subtractedBy(phantom, reco);
recoDiff3.show("RecoDiff NoFilter" + iter);
}
}
}
/*
* Copyright (C) 2010-2014 Salaheldin Saleh, me@s-saleh.com
* CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
*/