@Override public void workOnSlice(int sliceNumber) { PrioritizableScene phantomScene = phantom; if (phantom instanceof AnalyticPhantom4D) { AnalyticPhantom4D scene4D = (AnalyticPhantom4D) phantom; phantomScene = scene4D.getScene(((double) sliceNumber) / trajectory.getProjectionStackSize()); String disableAutoCenterBoolean = Configuration.getGlobalConfiguration() .getRegistryEntry(RegKeys.DISABLE_CENTERING_4DPHANTOM_PROJECTION_RENDERING); boolean disableAutoCenter = false; if (disableAutoCenterBoolean != null) { disableAutoCenter = Boolean.parseBoolean(disableAutoCenterBoolean); } Translation centerTranslation = new Translation(new SimpleVector(0, 0, 0)); if (!disableAutoCenter) { SimpleVector center = SimpleOperators.add( phantom.getMax().getAbstractVector(), phantom.getMin().getAbstractVector()) .dividedBy(2); centerTranslation = new Translation(center.negated()); } for (PhysicalObject o : phantomScene) { o.getShape().applyTransform(centerTranslation); // System.out.println(o.getShape().getMax() + " " + o.getShape().getMin()); // Translate a part of XCAT to the center of source & detector for 2D projection (e.g. knee // at the center of the 2d projection) String translationString = Configuration.getGlobalConfiguration() .getRegistryEntry(RegKeys.GLOBAL_TRANSLATION_4DPHANTOM_PROJECTION_RENDERING); if (translationString != null) { // Center b/w RKJC & LKJC: -292.6426 211.7856 440.7783 (subj 5, static60),-401.1700 // 165.9885 478.5600 (subj 2, static60) // XCAT Center by min & max: -177.73999504606988, 179.8512744259873, 312.19713254613583 // translationVector = (XCAT Center by min & max) - (Center b/w RKJC & LKJC)=> // 114.9026, -31.9343, -128.5811 (subj5), 120, 3, -110(subj2) Try 114.0568 2.4778 // -106.2550 String[] values = translationString.split(", "); SimpleVector translationVector = new SimpleVector( Double.parseDouble(values[0]), Double.parseDouble(values[1]), Double.parseDouble(values[2])); Translation translationToRotationCenter = new Translation(translationVector); o.getShape().applyTransform(translationToRotationCenter); } } // System.out.println(phantomScene.getMax() + " " + phantomScene.getMin()); } Grid2D slice = raytraceScene(phantomScene, trajectory.getProjectionMatrix(sliceNumber)); this.imageBuffer.add(slice, sliceNumber); }
public DefrisePhantom() { Trajectory trajectory = Configuration.getGlobalConfiguration().getGeometry(); double sourceAxisDistance = trajectory.getSourceToAxisDistance(); double sourceDetectorDistance = trajectory.getSourceToDetectorDistance(); double detectorYAxis = trajectory.getDetectorHeight() * trajectory.getPixelDimensionY(); double detectorXAxis = trajectory.getDetectorWidth() * trajectory.getPixelDimensionX(); double fovRadius = detectorXAxis * sourceAxisDistance / sourceDetectorDistance / 2 * 0.95; double diskRadius = 4.0 / 5.0 * fovRadius; double fovHeight = detectorYAxis * sourceAxisDistance / sourceDetectorDistance; double diskHeight = fovHeight / 15.0; double diskSpacing = fovHeight / 15.0; int numDisks = 5; double diskStart = -(fovHeight / 2.0) + ((fovHeight - (numDisks * diskHeight + diskSpacing * (numDisks - 1))) / 2.0) + diskHeight / 2.0; // Water Body Cylinder cyl = new Cylinder(fovRadius, fovRadius, fovHeight); cyl.setName("Water-like body of the phantom"); PhysicalObject po = new PhysicalObject(); po.setMaterial(MaterialsDB.getMaterialWithName("Water")); // D = 1.0 po.setShape(cyl); add(po); // Disk Inserts for (int i = 0; i < numDisks; i++) { cyl = new Cylinder(diskRadius, diskRadius, diskHeight); cyl.setName("Disk"); cyl.applyTransform( new Translation(new SimpleVector(0, 0, diskStart + (diskSpacing + diskHeight) * i))); po = new PhysicalObject(); po.setMaterial(MaterialsDB.getMaterialWithName("Plexiglass")); // D = 1.95 po.setShape(cyl); add(po); } }
public Grid2D raytraceScene(PrioritizableScene phantomScene, Projection projection) { Trajectory geom = Configuration.getGlobalConfiguration().getGeometry(); // Grid2D slice = new Grid2D(geom.getDetectorWidth(), geom.getDetectorHeight()); Grid2D slice = detector.createDetectorGrid(geom.getDetectorWidth(), geom.getDetectorHeight(), projection); rayTracer.setScene(phantomScene); // Second rule of optimization is: Optimize later. PointND raySource = new PointND(0, 0, 0); raySource.setCoordinates(projection.computeCameraCenter()); StraightLine castLine = new StraightLine(raySource, new SimpleVector(0, 0, 0)); SimpleVector centerPixDir = null; if (accurate) { centerPixDir = projection.computePrincipalAxis(); } // SimpleVector prinpoint = trajectory.getProjectionMatrix(sliceNumber).getPrincipalPoint(); double xcorr = 0; // trajectory.getDetectorWidth()/2 - prinpoint.getElement(0); double ycorr = 0; // trajectory.getDetectorHeight()/2 - prinpoint.getElement(1); double length = trajectory.getSourceToDetectorDistance(); Edge environmentEdge = new Edge(new PointND(0), new PointND(length)); ArrayList<PhysicalObject> fallBackBackground = new ArrayList<PhysicalObject>(1); SimpleVector pixel = new SimpleVector(0, 0); boolean negate = false; for (int y = 0; y < trajectory.getDetectorHeight(); y++) { for (int x = 0; x < trajectory.getDetectorWidth(); x++) { pixel.setElementValue(0, x - xcorr); pixel.setElementValue(1, y - ycorr); SimpleVector dir = projection.computeRayDirection(pixel); if ((y == 0) && (x == 0)) { // Check that ray direction is towards origin. double max = 0; int index = 0; for (int i = 0; i < 3; i++) { if (Math.abs(dir.getElement(i)) > max) { max = Math.abs(dir.getElement(i)); index = i; } } double t = -raySource.get(index) / dir.getElement(index); if (t < 0) negate = true; } if (negate) dir.negate(); castLine.setDirection(dir); ArrayList<PhysicalObject> segments = rayTracer.castRay(castLine); if (accurate) { double dirCosine = SimpleOperators.multiplyInnerProd(centerPixDir, dir); length = trajectory.getSourceToDetectorDistance() / dirCosine; } if (segments == null) { fallBackBackground.clear(); segments = fallBackBackground; } else { if (accurate) { environmentEdge = new Edge(new PointND(0), new PointND(length - getTotalSegmentsLength(segments))); } } environment.setShape(environmentEdge); segments.add(environment); /* old code: double integral = absorptionModel.evaluateLineIntegral(segments); slice.putPixelValue(x, y, integral); */ detector.writeToDetector(slice, x, y, segments); } } return slice; }