import java.io.File;
import java.util.ArrayList;
import javax.swing.JFileChooser;
import edu.stanford.rsl.conrad.geometry.Rotations;
import edu.stanford.rsl.conrad.geometry.shapes.simple.PointND;
import edu.stanford.rsl.conrad.geometry.trajectories.ProjectionTableFileTrajectory;
import edu.stanford.rsl.conrad.geometry.trajectories.Trajectory;
import edu.stanford.rsl.conrad.numerics.SimpleMatrix;
import edu.stanford.rsl.conrad.numerics.SimpleOperators;
import edu.stanford.rsl.conrad.numerics.SimpleVector;
import edu.stanford.rsl.conrad.utils.DoublePrecisionPointUtil;
import edu.stanford.rsl.conrad.utils.StringFileFilter;
import ij.plugin.PlugIn;
public class Check_Trajectory_Consistency implements PlugIn {
@Override
public void run(String arg) {
try {
JFileChooser FC = new JFileChooser();
if (arg != null){
File dir = new File(arg);
FC.setCurrentDirectory(dir);
}
FC.setVisible(true);
FC.setFileFilter(new StringFileFilter(".txt"));
FC.setMultiSelectionEnabled(true);
int result = -1;
result = FC.showOpenDialog(null);
if (result == JFileChooser.CANCEL_OPTION) {
throw new Exception("Cancelled");
}
File [] files = FC.getSelectedFiles();
Trajectory [] trajectories = new Trajectory[files.length];
int numProj = -1;
for (int i = 0; i < files.length; i++){
trajectories[i]= new ProjectionTableFileTrajectory(files[i].getAbsolutePath(), new Trajectory());
if (numProj == -1) numProj = trajectories[i].getProjectionMatrices().length;
else {
if (numProj != trajectories[i].getProjectionMatrices().length) throw new RuntimeException("Number of matrices does not match!");
}
}
// compute reference iso center
PointND referenceCenter = trajectories[0].computeIsoCenter();
// compute reference source positions centered around (0, 0, 0);
ArrayList<PointND> refPositions = computeCenteredSourcePositions(trajectories[0], referenceCenter);
ArrayList<PointND> refPoints = computePrincipalPoints(trajectories[0]);
// estimate normalization rotation matrix
SimpleMatrix referenceRotation = estimateRotationMatrix(refPositions);
// apply rotation to all source postions
applyRotation(refPositions, referenceRotation);
System.out.println("Isocenter\tmean deviation [mm] \tcoordinates");
printSourcePositions(files[0].getAbsolutePath(), referenceCenter, 0, refPositions, refPoints);
for (int i = 1; i < files.length; i++){
// estimate the iso center
PointND otherIsoCenter = trajectories[i].computeIsoCenter();
ArrayList<PointND> otherTrajectory = computeCenteredSourcePositions(trajectories[i], otherIsoCenter);
SimpleMatrix otherRotation = estimateRotationMatrix(otherTrajectory);
applyRotation(otherTrajectory, otherRotation);
double deviation = computeMeanDeviation(refPositions, otherTrajectory);
printSourcePositions(files[i].getAbsolutePath(), otherIsoCenter, deviation, otherTrajectory, computePrincipalPoints(trajectories[i]));
}
printSourcePositions(files[0].getAbsolutePath(), referenceCenter, 0, refPositions, refPoints);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public double computeMeanDeviation(ArrayList<PointND> pointsA, ArrayList<PointND> pointsB){
double sum = 0;
for (int i = 0; i < pointsA.size(); i++){
sum += (pointsA.get(i).euclideanDistance(pointsB.get(i)));
}
return sum / pointsA.size();
}
/**
* Prints the important features of the trajectory
* @param isocenter the iso center
* @param deviation the mean deviation
* @param points the actual source positions
* @param principalPoints
*/
public void printSourcePositions(String file, PointND isocenter, double deviation, ArrayList<PointND> points, ArrayList<PointND> principalPoints){
System.out.print(file +"\t"+isocenter + "\t" + deviation+"\t");
System.out.print(DoublePrecisionPointUtil.getGeometricCenter(principalPoints) + "\t" + DoublePrecisionPointUtil.getStandardDeviation(principalPoints)+"\t");
for (int i =0; i < points.size(); i++){
System.out.print(points.get(i)+"\t");
}
System.out.println();
}
/**
* Method to generate all the principal points of the detectors in pixels.
* @param traj the trajectory
* @return the source positions centered around (0, 0, 0);
*/
public ArrayList<PointND> computePrincipalPoints(Trajectory traj){
ArrayList<PointND> refPositions = new ArrayList<PointND>();
for (int i = 0; i < traj.getProjectionMatrices().length; i++){
SimpleVector vector = traj.getProjectionMatrices()[i].getPrincipalPoint();
PointND point = new PointND(vector);
refPositions.add(point);
}
return refPositions;
}
/**
* Method to move points around the iso center, i.e. a translation is applied.
* @param traj the trajectory
* @param isoCenter the iso center
* @return the source positions centered around (0, 0, 0);
*/
public ArrayList<PointND> computeCenteredSourcePositions(Trajectory traj, PointND isoCenter){
ArrayList<PointND> refPositions = new ArrayList<PointND>();
for (int i = 0; i < traj.getProjectionMatrices().length; i++){
SimpleVector vector = traj.getProjectionMatrices()[i].computeCameraCenter();
traj.getProjectionMatrices()[i].computeRayDirection(new SimpleVector(0,0));
vector.add(isoCenter.getAbstractVector().negated());
PointND point = new PointND(vector);
refPositions.add(point);
}
return refPositions;
}
/**
* estimates the rotation that needs to be applied to move the first source position to the vector<br>
* ( normL2(firstSourcePosition), 0, 0) <br>
* Using this transformation the trajectory can be standardized. Coordinates will still me metric, but centered around (0, 0, 0)
*
* @param centeredPoints
* @return the rotation matrix
*/
public SimpleMatrix estimateRotationMatrix (ArrayList<PointND> centeredPoints){
SimpleVector other = centeredPoints.get(0).getAbstractVector();
double len = other.normL2();
SimpleVector e1 = new SimpleVector(len, 0, 0);
return Rotations.getRotationMatrixFromAtoB(other, e1);
}
/**
* Method to apply a rotation matrix to a set of points.
* @param points
* @param rotation
*/
public void applyRotation(ArrayList<PointND> points, SimpleMatrix rotation){
for (PointND point:points){
SimpleVector newCoord = SimpleOperators.multiply(rotation, point.getAbstractVector());
point.setCoordinates(newCoord);
}
}
public static void main(String [] args){
new Check_Trajectory_Consistency().run("C:\\Users\\z002xsyz\\Documents\\4yu\\5s\\forward");
}
}
/*
* Copyright (C) 2010-2014 - Andreas Maier
* CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
*/