@Override public void configure() throws Exception { Configuration config = Configuration.getGlobalConfiguration(); setConfiguration(config); // double [] minmax = null; checkDelta(); setNumberOfProjections(config.getGeometry().getPrimaryAngles().length); double maxRange = (Math.PI + (2 * delta)); if (getPrimaryAngles() != null) { // minmax = DoubleArrayUtil.minAndMaxOfArray(primaryAngles); double factor = 15 - (deltaX / Math.PI * 180); if (factor < 1) factor = 1; double range = (computeScanRange() + (factor * config.getGeometry().getAverageAngularIncrement())) * Math.PI / 180.0; offset = ((maxRange - range) / 2); offset = factor * config.getGeometry().getAverageAngularIncrement() / 180.0 * Math.PI / 2; deltaX = range - Math.PI; if (debug) System.out.println("delta: " + delta * 180 / Math.PI); if (debug) System.out.println("Angular Offset: " + offset + " " + maxRange + " " + range); if (debug) System.out.println("deltaX: " + deltaX); } if (this.numberOfProjections == 0) { throw new Exception("Number of projections not known"); } setConfigured(true); }
@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); }
/** * feeds the filter from a projection Source. * * @param source the source * @param showStatus displays whether the status should be displayed using ImageJ * @throws Exception may happen. */ public void feedFilter(ProjectionSource source, boolean showStatus) throws Exception { // Stream data into filter int stackSize = Configuration.getGlobalConfiguration().getGeometry().getProjectionStackSize(); for (int i = 0; i < stackSize; i++) { process(source.getNextProjection(), i); } }
public void reconstructOffline(ImagePlus imagePlus) throws Exception { ImagePlusDataSink sink = new ImagePlusDataSink(); configure(); init(); for (int i = 0; i < imagePlus.getStackSize(); i++) { backproject(ImageUtil.wrapImageProcessor(imagePlus.getStack().getProcessor(i + 1)), i); } waitForResult(); if (Configuration.getGlobalConfiguration().getUseHounsfieldScaling()) applyHounsfieldScaling(); int[] size = projectionVolume.getSize(); System.out.println(size[0] + " " + size[1] + " " + size[2]); for (int k = 0; k < projectionVolume.getSize()[2]; k++) { FloatProcessor fl = new FloatProcessor(projectionVolume.getSize()[0], projectionVolume.getSize()[1]); for (int j = 0; j < projectionVolume.getSize()[1]; j++) { for (int i = 0; i < projectionVolume.getSize()[0]; i++) { fl.putPixelValue(i, j, projectionVolume.getAtIndex(i, j, k)); } } sink.process(projectionVolume.getSubGrid(k), k); } sink.close(); ImagePlus revan = ImageUtil.wrapGrid3D(sink.getResult(), "Reconstruction of " + imagePlus.getTitle()); revan.setTitle(imagePlus.getTitle() + " reconstructed"); revan.show(); reset(); }
@Test public void testCreateVolume() { Configuration.loadConfiguration(); Volume3D vol = op.createVolume(size, dim, 1); CUDAVolume3D cudaVol = (CUDAVolume3D) cuop.createVolume(size, dim, 1); cudaVol.fetch(); assertVolumeEquality(vol, cudaVol); cudaVol.destroy(); vol.destroy(); }
@Test public void testfilt_gauss() { Configuration.loadConfiguration(); cuop.initCUDA(); Volume3D one = op.createGaussLowPassFilter(3, size, dim, 2); CUDAVolume3D cudaVol = (CUDAVolume3D) cuop.createGaussLowPassFilter(3, size, dim, 2); cudaVol.fetch(); assertVolumeEquality(one, cudaVol); cudaVol.destroy(); one.destroy(); }
protected Grid3D reconstructCL(double[] motionfield) { init(); int n = inputQueue.size(); for (int i = 0; i < n; i++) { backproject(inputQueue.get(i), i); } waitForResult(motionfield); if (Configuration.getGlobalConfiguration().getUseHounsfieldScaling()) applyHounsfieldScaling(); // projectionVolume.show(); return projectionVolume; }
@Test public void testMin() { Configuration.loadConfiguration(); Volume3D one = createRandomVolume(); cuop.initCUDA(); CUDAVolume3D cudaVol = createCUDACopy(one); float cpu = op.min(one); float gpu = cuop.min(cudaVol); cudaVol.fetch(); org.junit.Assert.assertTrue(cpu == gpu); cudaVol.destroy(); one.destroy(); }
@Test public void testDivideScalar() { Configuration.loadConfiguration(); Volume3D one = createRandomVolume(); cuop.initCUDA(); CUDAVolume3D cudaVol = createCUDACopy(one); op.divideScalar(one, 3.0f, 0.0f); cuop.divideScalar(cudaVol, 3.0f, 0.0f); cudaVol.fetch(); assertVolumeEquality(one, cudaVol); cudaVol.destroy(); one.destroy(); }
@Test public void testAbs() { Configuration.loadConfiguration(); Volume3D one = createRandomVolume(); cuop.initCUDA(); CUDAVolume3D cudaVol = createCUDACopy(one); op.abs(one); cuop.abs(cudaVol); cudaVol.fetch(); assertVolumeEquality(one, cudaVol); cudaVol.destroy(); one.destroy(); }
public static void main(String[] args) { CONRAD.setup(); Configuration config = Configuration.getGlobalConfiguration(); CircularTrajectory traj = new CircularTrajectory(config.getGeometry()); double[] startAngles = new double[] {0, 20, 40}; for (int j = 0; j < startAngles.length; j++) { traj.setTrajectory( 2, 600, 90, 0, 0, CameraAxisDirection.ROTATIONAXIS_PLUS, CameraAxisDirection.DETECTORMOTION_PLUS, new SimpleVector(0, 0, 1), new PointND(0, 0, 0), startAngles[j]); for (int i = 0; i < traj.getNumProjectionMatrices(); i++) { System.out.println("Matrix: " + traj.getProjectionMatrix(i).toString()); } System.out.println(" "); } }
@Test public void testMean() { Configuration.loadConfiguration(); Volume3D one = createRandomVolume(); cuop.initCUDA(); CUDAVolume3D cudaVol = createCUDACopy(one); float cpu = op.mean(one); float gpu = cuop.mean(cudaVol); cudaVol.fetch(); // System.out.println(cpu + " " + gpu); org.junit.Assert.assertTrue(Math.abs(cpu - gpu) < 0.00001); cudaVol.destroy(); one.destroy(); }
@Override protected void reconstruct() throws Exception { init(); for (int i = 0; i < nImages; i++) { backproject(inputQueue.get(i), i); } waitForResult(); if (Configuration.getGlobalConfiguration().getUseHounsfieldScaling()) applyHounsfieldScaling(); int[] size = projectionVolume.getSize(); for (int k = 0; k < size[2]; k++) { sink.process(projectionVolume.getSubGrid(k), k); } sink.close(); }
@Test public void testfilt_cos2_quad() { Configuration.loadConfiguration(); cuop.initCUDA(); float[][] dirs = new float[6][3]; AnisotropicFilterFunction.filt_get_filt_dirs(3, dirs); Volume3D one = op.createDirectionalWeights(3, size, dim, dirs[0], 1, VolumeOperator.FILTER_TYPE.QUADRATIC); CUDAVolume3D cudaVol = (CUDAVolume3D) cuop.createDirectionalWeights( 3, size, dim, dirs[0], 1, VolumeOperator.FILTER_TYPE.QUADRATIC); cudaVol.fetch(); assertVolumeEquality(one, cudaVol); cudaVol.destroy(); one.destroy(); }
@Test public void testAddVolumeWeight() { Configuration.loadConfiguration(); Volume3D one = createRandomVolume(); Volume3D two = createRandomVolume(); cuop.initCUDA(); CUDAVolume3D cudaVol = createCUDACopy(one); CUDAVolume3D cudaVol2 = createCUDACopy(two); op.addVolume(one, two, 2.0); cuop.addVolume(cudaVol, cudaVol2, 2.0); cudaVol.fetch(); assertVolumeEquality(one, cudaVol); cudaVol.destroy(); cudaVol2.destroy(); one.destroy(); two.destroy(); }
@Test public void testfilt_cos2r() { Configuration.loadConfiguration(); cuop.initCUDA(); float[][] dirs = new float[6][3]; AnisotropicFilterFunction.filt_get_filt_dirs(3, dirs); Volume3D one = op.createExponentialDirectionalHighPassFilter( 3, size, dim, dirs[0], 1, 2.0f, 1.5f, VolumeOperator.FILTER_TYPE.NORMAL); CUDAVolume3D cudaVol = (CUDAVolume3D) cuop.createExponentialDirectionalHighPassFilter( 3, size, dim, dirs[0], 1, 2.0f, 1.5f, VolumeOperator.FILTER_TYPE.NORMAL); cudaVol.fetch(); assertVolumeEquality(one, cudaVol); cudaVol.destroy(); one.destroy(); }
@Test public void testDivideByVolume() { Configuration.loadConfiguration(); Volume3D one = createRandomVolume(); Volume3D two = createRandomVolume(); op.multiplyScalar(one, 1000, 0); op.addScalar(two, 10, 0); cuop.initCUDA(); CUDAVolume3D cudaVol = createCUDACopy(one); CUDAVolume3D cudaVol2 = createCUDACopy(two); op.divideByVolume(one, two); cuop.divideByVolume(cudaVol, cudaVol2); cudaVol.fetch(); assertWeakVolumeEquality(one, cudaVol); cudaVol.destroy(); cudaVol2.destroy(); one.destroy(); two.destroy(); }
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); } }
@Override public void configure() throws Exception { // We will now read this from the Configuration. The detector needs to be preconfigured! // detector = (XRayDetector) UserUtil.queryObject("Select Detector:", "Detector Selection", // XRayDetector.class); // detector.configure(); detector = Configuration.getGlobalConfiguration().getDetector(); detector.init(); phantom = UserUtil.queryPhantom("Select Phantom", "Select Phantom"); Material mat = null; do { String materialstr = UserUtil.queryString("Enter Background Medium:", "vacuum"); mat = MaterialsDB.getMaterialWithName(materialstr); } while (mat == null); phantom.setBackground(mat); phantom.configure(); rayTracer.setScene((PrioritizableScene) phantom); environment.setMaterial(phantom.getBackgroundMaterial()); super.configure(); }
@Override public void configure() throws Exception { slope = UserUtil.queryDouble("Enter slope of correction transformatoin", slope); // offset = UserUtil.queryDouble("Enter offset of correction transformation", offset); measureHard = UserUtil.queryDouble("Measurement of hard material [HU]", measureHard); measureSoft = UserUtil.queryDouble("Measurement of soft material [HU]", measureSoft); projectionXShift = UserUtil.queryDouble("Enter projection x shift", projectionXShift); projectionYShift = UserUtil.queryDouble("Enter projection y shift", projectionYShift); lambda0 = VolumeAttenuationFactorCorrectionTool.getLambda0(measureHard, measureSoft); lut = Configuration.getGlobalConfiguration().getBeamHardeningLookupTable(); ImagePlus[] images = ImageUtil.getAvailableImagePlusAsArray(); hardMaterial = ImageUtil.wrapImagePlus( (ImagePlus) JOptionPane.showInputDialog( null, "Select projections with hard material: ", "Select source", JOptionPane.PLAIN_MESSAGE, null, images, images[0])); configured = true; }
@Test public void testfilt_solve_max_eigenValue() { Configuration.loadConfiguration(); cuop.initCUDA(); int[] size = {30, 30, 30}; this.size = size; float[][] dirs = new float[6][3]; AnisotropicFilterFunction.filt_get_filt_dirs(3, dirs); Volume3D a11 = op.createExponentialDirectionalHighPassFilter( 3, size, dim, dirs[0], 1, 2.0f, 1.5f, VolumeOperator.FILTER_TYPE.QUADRATIC); Volume3D a12 = op.createExponentialDirectionalHighPassFilter( 3, size, dim, dirs[1], 1, 2.0f, 1.5f, VolumeOperator.FILTER_TYPE.QUADRATIC); Volume3D a13 = op.createExponentialDirectionalHighPassFilter( 3, size, dim, dirs[2], 1, 2.0f, 1.5f, VolumeOperator.FILTER_TYPE.QUADRATIC); Volume3D a22 = op.createExponentialDirectionalHighPassFilter( 3, size, dim, dirs[3], 1, 2.0f, 1.5f, VolumeOperator.FILTER_TYPE.QUADRATIC); Volume3D a23 = op.createExponentialDirectionalHighPassFilter( 3, size, dim, dirs[4], 1, 2.0f, 1.5f, VolumeOperator.FILTER_TYPE.QUADRATIC); Volume3D a33 = op.createExponentialDirectionalHighPassFilter( 3, size, dim, dirs[5], 1, 2.0f, 1.5f, VolumeOperator.FILTER_TYPE.QUADRATIC); op.real(a11); op.real(a12); op.real(a13); op.real(a22); op.real(a23); op.real(a33); Volume3D[][] st = new Volume3D[3][3]; st[0][0] = a11; st[0][1] = a12; st[0][2] = a13; st[1][0] = a12; st[1][1] = a22; st[1][2] = a23; st[2][0] = a13; st[2][1] = a23; st[2][2] = a33; CUDAVolume3D ca11 = (CUDAVolume3D) cuop.createExponentialDirectionalHighPassFilter( 3, size, dim, dirs[0], 1, 2.0f, 1.5f, VolumeOperator.FILTER_TYPE.QUADRATIC); CUDAVolume3D ca12 = (CUDAVolume3D) cuop.createExponentialDirectionalHighPassFilter( 3, size, dim, dirs[1], 1, 2.0f, 1.5f, VolumeOperator.FILTER_TYPE.QUADRATIC); CUDAVolume3D ca13 = (CUDAVolume3D) cuop.createExponentialDirectionalHighPassFilter( 3, size, dim, dirs[2], 1, 2.0f, 1.5f, VolumeOperator.FILTER_TYPE.QUADRATIC); CUDAVolume3D ca22 = (CUDAVolume3D) cuop.createExponentialDirectionalHighPassFilter( 3, size, dim, dirs[3], 1, 2.0f, 1.5f, VolumeOperator.FILTER_TYPE.QUADRATIC); CUDAVolume3D ca23 = (CUDAVolume3D) cuop.createExponentialDirectionalHighPassFilter( 3, size, dim, dirs[4], 1, 2.0f, 1.5f, VolumeOperator.FILTER_TYPE.QUADRATIC); CUDAVolume3D ca33 = (CUDAVolume3D) cuop.createExponentialDirectionalHighPassFilter( 3, size, dim, dirs[5], 1, 2.0f, 1.5f, VolumeOperator.FILTER_TYPE.QUADRATIC); cuop.real(ca11); cuop.real(ca12); cuop.real(ca13); cuop.real(ca22); cuop.real(ca23); cuop.real(ca33); CUDAVolume3D[][] cst = new CUDAVolume3D[3][3]; cst[0][0] = ca11; cst[0][1] = ca12; cst[0][2] = ca13; cst[1][1] = ca22; cst[1][2] = ca23; cst[2][2] = ca33; // new ImageJ(); Volume3D one = op.solveMaximumEigenvalue(st); // one.getImagePlus("CPU Result").show(); CUDAVolume3D cudaVol = (CUDAVolume3D) cuop.solveMaximumEigenvalue(cst); cudaVol.fetch(); // cudaVol.getImagePlus("CUDA Result").show(); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } assertWeakVolumeEquality(one, cudaVol); a11.destroy(); a12.destroy(); a13.destroy(); a22.destroy(); a23.destroy(); a33.destroy(); ca11.destroy(); ca12.destroy(); ca13.destroy(); ca22.destroy(); ca23.destroy(); ca33.destroy(); cudaVol.destroy(); one.destroy(); }
protected void init() { if (!initialized) { largeVolumeMode = false; int reconDimensionX = getGeometry().getReconDimensionX(); int reconDimensionY = getGeometry().getReconDimensionY(); int reconDimensionZ = getGeometry().getReconDimensionZ(); projectionsAvailable = new ArrayList<Integer>(); projectionsDone = new ArrayList<Integer>(); // Initialize JOCL. context = OpenCLUtil.createContext(); try { // get the fastest device device = context.getMaxFlopsDevice(); // create the command queue commandQueue = device.createCommandQueue(); // initialize the program if (program == null || !program.getContext().equals(this.context)) { program = context .createProgram( OpenCLCompensatedBackProjector.class.getResourceAsStream( "compensatedBackprojectCL.cl")) .build(); } } catch (Exception e) { if (commandQueue != null) commandQueue.release(); if (kernelFunction != null) kernelFunction.release(); if (program != null) program.release(); // destory context if (context != null) context.release(); // TODO: handle exception e.printStackTrace(); } // check space on device: long memory = device.getMaxMemAllocSize(); long availableMemory = (memory); long requiredMemory = (long) (((((double) reconDimensionX) * reconDimensionY * ((double) reconDimensionZ) * 4) + (((double) Configuration.getGlobalConfiguration().getGeometry().getDetectorHeight()) * Configuration.getGlobalConfiguration().getGeometry().getDetectorWidth() * 4))); if (debug) { System.out.println("Total available Memory on OpenCL card:" + availableMemory); System.out.println("Required Memory on OpenCL card:" + requiredMemory); } if (requiredMemory > availableMemory) { nSteps = (int) OpenCLUtil.iDivUp(requiredMemory, availableMemory); if (debug) System.out.println("Switching to large volume mode with nSteps = " + nSteps); largeVolumeMode = true; } if (debug) { // TODO replace /* CUdevprop prop = new CUdevprop(); JCudaDriver.cuDeviceGetProperties(prop, dev); System.out.println(prop.toFormattedString()); */ } // create the computing kernel kernelFunction = program.createCLKernel("backprojectKernel"); // create the reconstruction volume; int memorysize = reconDimensionX * reconDimensionY * reconDimensionZ * 4; if (largeVolumeMode) { subVolumeZ = OpenCLUtil.iDivUp(reconDimensionZ, nSteps); if (debug) System.out.println("SubVolumeZ: " + subVolumeZ); h_volume = new float[reconDimensionX * reconDimensionY * subVolumeZ]; memorysize = reconDimensionX * reconDimensionY * subVolumeZ * 4; if (debug) System.out.println("Memory: " + memorysize); } else { h_volume = new float[reconDimensionX * reconDimensionY * reconDimensionZ]; } // compute adapted volume size // volume size in x = multiple of bpBlockSize[0] // volume size in y = multiple of bpBlockSize[1] int adaptedVolSize[] = new int[3]; if ((reconDimensionX % bpBlockSize[0]) == 0) { adaptedVolSize[0] = reconDimensionX; } else { adaptedVolSize[0] = ((reconDimensionX / bpBlockSize[0]) + 1) * bpBlockSize[0]; } if ((reconDimensionY % bpBlockSize[1]) == 0) { adaptedVolSize[1] = reconDimensionY; } else { adaptedVolSize[1] = ((reconDimensionY / bpBlockSize[1]) + 1) * bpBlockSize[1]; } adaptedVolSize[2] = reconDimensionZ; int volStrideHost[] = new int[2]; // compute volstride and copy it to constant memory volStrideHost[0] = adaptedVolSize[0]; volStrideHost[1] = adaptedVolSize[0] * adaptedVolSize[1]; // copy volume to device volumePointer = context.createFloatBuffer(h_volume.length, Mem.WRITE_ONLY); volumePointer.getBuffer().put(h_volume); volumePointer.getBuffer().rewind(); // copy volume stride to device volStride = context.createIntBuffer(volStrideHost.length, Mem.READ_ONLY); volStride.getBuffer().put(volStrideHost); volStride.getBuffer().rewind(); commandQueue.putWriteBuffer(volumePointer, true).putWriteBuffer(volStride, true).finish(); initialized = true; } }
/** * Projects arbitrarily defined phantoms to a detector using ray casting.<br> * The pixel value on the detector is determined by the absorption model.<br> * <br> * <b>If you change anything in this class, notify the conrad-dev mailing list.</b> * * @author Rotimi X Ojo * @author Andreas Maier */ public class AnalyticPhantomProjectorWorker extends SliceWorker { protected AnalyticPhantom phantom; protected Trajectory trajectory = Configuration.getGlobalConfiguration().getGeometry(); private XRayDetector detector; private PriorityRayTracer rayTracer = new PriorityRayTracer(); private static boolean accurate = false; // First rule of optimization is: Don't optimize! // Start for speed up // private StraightLine castLine = new StraightLine(new PointND(0,0,0),new SimpleVector(0,0,0)); // private SimpleVector pixel = new SimpleVector(0, 0); // private ArrayList<PhysicalObject> segmentsBuff = new ArrayList<PhysicalObject> (1); private PhysicalObject environment = new PhysicalObject(); // private PointND startPoint = new PointND(0,0); // private PointND endPoint = new PointND(0,0); // private Edge environmentEdge = new Edge(startPoint, endPoint); // private PointND raySource = new PointND(0,0,0); // End for speed up @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 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; } private double getTotalSegmentsLength(ArrayList<PhysicalObject> segments) { double sum = 0; Iterator<PhysicalObject> it = segments.iterator(); while (it.hasNext()) { // sum+=((Edge) it.next().getShape()).getLength(); } return sum; } public SliceWorker clone() { AnalyticPhantomProjectorWorker newRend = new AnalyticPhantomProjectorWorker(); newRend.phantom = phantom; newRend.detector = detector; newRend.environment.setMaterial(phantom.getBackgroundMaterial()); newRend.rayTracer.setScene((PrioritizableScene) phantom); return newRend; } @Override public void configure() throws Exception { // We will now read this from the Configuration. The detector needs to be preconfigured! // detector = (XRayDetector) UserUtil.queryObject("Select Detector:", "Detector Selection", // XRayDetector.class); // detector.configure(); detector = Configuration.getGlobalConfiguration().getDetector(); detector.init(); phantom = UserUtil.queryPhantom("Select Phantom", "Select Phantom"); Material mat = null; do { String materialstr = UserUtil.queryString("Enter Background Medium:", "vacuum"); mat = MaterialsDB.getMaterialWithName(materialstr); } while (mat == null); phantom.setBackground(mat); phantom.configure(); rayTracer.setScene((PrioritizableScene) phantom); environment.setMaterial(phantom.getBackgroundMaterial()); super.configure(); } public void configure(AnalyticPhantom phan, XRayDetector detector) throws Exception { this.detector = detector; this.detector.init(); phantom = phan; if (phantom.getBackgroundMaterial() == null) { Material mat = null; String materialstr = "vacuum"; mat = MaterialsDB.getMaterialWithName(materialstr); phantom.setBackground(mat); } rayTracer.setScene((PrioritizableScene) phantom); environment.setMaterial(phantom.getBackgroundMaterial()); super.configure(); } @Override public String getProcessName() { return "Generic Phantom Projector"; } @Override public String getBibtexCitation() { return CONRAD.CONRADBibtex; } @Override public String getMedlineCitation() { return CONRAD.CONRADMedline; } /** @return the absorptionModel */ public XRayDetector getDetector() { return detector; } /** @param absorptionModel the absorptionModel to set */ public void setDetector(XRayDetector detector) { this.detector = detector; } }
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; }
@Override public Grid2D applyToolToImage(Grid2D imageProcessor) { FloatProcessor imp = new FloatProcessor(imageProcessor.getWidth(), imageProcessor.getHeight()); imp.setPixels(imageProcessor.getBuffer()); if (!initBead) initializeBead(); ImageProcessor imp1 = imp.duplicate(); // original double[][] beadMean3D = config.getBeadMeanPosition3D(); // [beadNo][x,y,z] double[] uv = new double[1]; SimpleMatrix pMatrix = config.getGeometry().getProjectionMatrix(imageIndex).computeP(); // [projection #][bead #][u, v, state[0: initial, 1: registered, 2: updated by hough searching]] double[][][] beadPosition2D = config.getBeadPosition2D(); int noBeadRegistered = 0; double[][] xy1 = new double[WeightBearingBeadPositionBuilder.beadNo][2]; // original double[][] xy2 = new double[WeightBearingBeadPositionBuilder.beadNo] [2]; // warped (mapped to the mean), control points, reference double[][] xy1_hat = new double[WeightBearingBeadPositionBuilder.beadNo][2]; // original double[][] xy2_hat = new double[WeightBearingBeadPositionBuilder.beadNo][2]; // original // double distanceReferenceToCurrentBead = 0; for (int i = WeightBearingBeadPositionBuilder.currentBeadNo; i >= 0; i--) { if (beadMean3D[i][0] != 0 || beadMean3D[i][1] != 0 || beadMean3D[i][2] != 0) { // assume bead 3d is registered. uv = compute2DCoordinates(beadMean3D[i], pMatrix); // find bead location if registered by txt: state 1 if (beadPosition2D[imageIndex][i][2] == 1) { noBeadRegistered++; if (isDisplay) { imp1.setValue(2); imp1.drawLine( (int) Math.round(beadPosition2D[imageIndex][i][0] - 10), (int) Math.round(beadPosition2D[imageIndex][i][1] - 10), (int) Math.round(beadPosition2D[imageIndex][i][0] + 10), (int) Math.round(beadPosition2D[imageIndex][i][1] + 10)); imp1.drawLine( (int) Math.round(beadPosition2D[imageIndex][i][0] - 10), (int) Math.round(beadPosition2D[imageIndex][i][1] + 10), (int) Math.round(beadPosition2D[imageIndex][i][0] + 10), (int) Math.round(beadPosition2D[imageIndex][i][1] - 10)); imp1.drawString( "Bead " + i + " (state:" + (int) beadPosition2D[imageIndex][i][2] + ")", (int) beadPosition2D[imageIndex][i][0], (int) beadPosition2D[imageIndex][i][1] - 10); } xy1[noBeadRegistered - 1][0] = beadPosition2D[imageIndex][i][0]; xy1[noBeadRegistered - 1][1] = beadPosition2D[imageIndex][i][1]; xy2[noBeadRegistered - 1][0] = uv[0]; xy2[noBeadRegistered - 1][1] = uv[1]; } else if (imageIndex != 0 && imageIndex != config.getGeometry().getNumProjectionMatrices() - 1) { if (beadPosition2D[imageIndex - 1][i][2] == 1 && beadPosition2D[imageIndex + 1][i][2] == 1) { noBeadRegistered++; double xMean = (beadPosition2D[imageIndex - 1][i][0] + beadPosition2D[imageIndex - 1][i][0]) / 2; double yMean = (beadPosition2D[imageIndex + 1][i][1] + beadPosition2D[imageIndex + 1][i][1]) / 2; if (isDisplay) { imp1.setValue(2); imp1.drawLine( (int) Math.round(xMean - 10), (int) Math.round(yMean - 10), (int) Math.round(xMean + 10), (int) Math.round(yMean + 10)); imp1.drawLine( (int) Math.round(xMean - 10), (int) Math.round(yMean + 10), (int) Math.round(xMean + 10), (int) Math.round(yMean - 10)); imp1.drawString("Bead " + i + " (state:" + "M)", (int) xMean, (int) yMean - 10); } xy1[noBeadRegistered - 1][0] = xMean; xy1[noBeadRegistered - 1][1] = yMean; xy2[noBeadRegistered - 1][0] = uv[0]; xy2[noBeadRegistered - 1][1] = uv[1]; } } // mean projected bead // imp1.drawLine((int) Math.round(uv[0]-10), (int) Math.round(uv[1]), (int) // Math.round(uv[0]+10), (int) Math.round(uv[1])); // imp1.drawLine((int) Math.round(uv[0]), (int) Math.round(uv[1]-10), (int) // Math.round(uv[0]), (int) Math.round(uv[1]+10)); } } if (isDisplay) { for (int x = 0; x < config.getGeometry().getDetectorWidth(); x += 50) imp1.drawLine(x, 0, x, config.getGeometry().getDetectorHeight()); for (int y = 0; y < config.getGeometry().getDetectorHeight(); y += 50) imp1.drawLine(0, y, config.getGeometry().getDetectorWidth(), y); } if (isCornerIncluded) { xy1[noBeadRegistered + 0][0] = 0; xy1[noBeadRegistered + 0][1] = 0; xy2[noBeadRegistered + 0][0] = 0; xy2[noBeadRegistered + 0][1] = 0; xy1[noBeadRegistered + 1][0] = 0; xy1[noBeadRegistered + 1][1] = config.getGeometry().getDetectorHeight(); xy2[noBeadRegistered + 1][0] = 0; xy2[noBeadRegistered + 1][1] = config.getGeometry().getDetectorHeight(); xy1[noBeadRegistered + 2][0] = config.getGeometry().getDetectorWidth(); xy1[noBeadRegistered + 2][1] = 0; xy2[noBeadRegistered + 2][0] = config.getGeometry().getDetectorWidth(); xy2[noBeadRegistered + 2][1] = 0; xy1[noBeadRegistered + 3][0] = config.getGeometry().getDetectorWidth(); xy1[noBeadRegistered + 3][1] = config.getGeometry().getDetectorHeight(); xy2[noBeadRegistered + 3][0] = config.getGeometry().getDetectorWidth(); xy2[noBeadRegistered + 3][1] = config.getGeometry().getDetectorHeight(); noBeadRegistered = noBeadRegistered + 4; } boolean fScaling = true; double minX = Double.MAX_VALUE; double maxX = 0; double minY = Double.MAX_VALUE; double maxY = 0; double c = 0; if (fScaling) { // ----- scaling to reduce condition # of A matrix for (int i = 0; i < noBeadRegistered; i++) { minX = Math.min(minX, xy1[i][0]); maxX = Math.max(maxX, xy1[i][0]); minY = Math.min(minY, xy1[i][1]); maxY = Math.max(maxY, xy1[i][1]); } c = Math.max(maxX - minX, maxY - minY); for (int i = 0; i < noBeadRegistered; i++) { xy1_hat[i][0] = (xy1[i][0] - minX) / c; xy1_hat[i][1] = (xy1[i][1] - minY) / c; xy2_hat[i][0] = (xy2[i][0] - minX) / c; xy2_hat[i][1] = (xy2[i][1] - minY) / c; } } else { xy1_hat = xy1; xy2_hat = xy2; } ImageProcessor imp2 = imp1.duplicate(); // warped /* * A*x = b * Matrix A = (n + 3) * (n + 3); * n (noBeadRegistered + 4): # of control points + 4 corner points (assume corner points are static) */ int n = noBeadRegistered + 3; SimpleMatrix A = new SimpleMatrix(n, n); SimpleVector x_x = new SimpleVector(n); SimpleVector x_y = new SimpleVector(n); SimpleVector b_x = new SimpleVector(n); SimpleVector b_y = new SimpleVector(n); double rij = 0; double valA = 0; double valb_x = 0; double valb_y = 0; // Matrix L formation // alpha: mean of distances between control points' xy-projections) is a constant only present // on the diagonal of K // lambda: TPS smoothing regularization coefficient double alpha = 0.0; double lambda = 1.6; // 1.6 for (int i = 0; i < noBeadRegistered; i++) { // i= # of row for (int j = i; j < noBeadRegistered; j++) { // j= # of column alpha += Math.sqrt( Math.pow(xy2_hat[i][0] - xy2_hat[j][0], 2) + Math.pow(xy2_hat[i][1] - xy2_hat[j][1], 2)); } } alpha = alpha / Math.pow(noBeadRegistered, 2); for (int i = 0; i < n; i++) { // i= # of row for (int j = i; j < n; j++) { // j= # of column if (i < 3 && j < 3) valA = 0; else if (i >= 3 && j >= 3 && i == j) { valA = Math.pow(alpha, 2) * lambda; // valA = lambda; if (imageIndex < 10) System.out.println("Regularization = " + valA + ", lambda= " + lambda); } else if (i == 0 && j >= 0) valA = 1; else if (i == 1 && j >= 3) valA = xy1_hat[j - 3][0]; else if (i == 2 && j >= 3) valA = xy1_hat[j - 3][1]; else { rij = Math.pow(xy1_hat[j - 3][0] - xy1_hat[i - 3][0], 2) + Math.pow(xy1_hat[j - 3][1] - xy1_hat[i - 3][1], 2); if (rij == 0) valA = 0; else valA = rij * Math.log(rij); } A.setElementValue(i, j, valA); A.setElementValue(j, i, valA); } if (i < 3) { valb_x = 0; valb_y = 0; } else { // valb_x = xy2_hat[i-3][0]-xy1_hat[i-3][0]; // valb_y = xy2_hat[i-3][1]-xy1_hat[i-3][1]; valb_x = xy2[i - 3][0] - xy1[i - 3][0]; valb_y = xy2[i - 3][1] - xy1[i - 3][1]; // if (imageIndex > 150 && imageIndex < 170) // System.out.println("Idx" + imageIndex + ",Elevation" + (i-3) + ": " + valb_x + "---" // + valb_y); } b_x.setElementValue(i, valb_x); b_y.setElementValue(i, valb_y); } // System.out.println("A condition number=" + A.conditionNumber(MatrixNormType.MAT_NORM_L1)); // System.out.println("A condition number=" + A.conditionNumber(MatrixNormType.MAT_NORM_LINF)); x_x = Solvers.solveLinearSysytemOfEquations(A, b_x); x_y = Solvers.solveLinearSysytemOfEquations(A, b_y); if (fScaling) { // ----- pixel space coefficients a, b scaling back double tmpA0 = x_x.getElement(0) - x_x.getElement(1) * (minX / c) - x_x.getElement(2) * (minY / c); for (int j = 0; j < noBeadRegistered; j++) { tmpA0 -= Math.log(c) * 2 * x_x.getElement(j + 3) * (Math.pow(xy1_hat[j][0], 2) + Math.pow(xy1_hat[j][1], 2)); } x_x.setElementValue(0, tmpA0); tmpA0 = x_y.getElement(0) - x_y.getElement(1) * (minX / c) - x_y.getElement(2) * (minY / c); for (int j = 0; j < noBeadRegistered; j++) { tmpA0 -= Math.log(c) * 2 * x_y.getElement(j + 3) * (Math.pow(xy1_hat[j][0], 2) + Math.pow(xy1_hat[j][1], 2)); } x_y.setElementValue(0, tmpA0); x_x.setElementValue(1, x_x.getElement(1) / c); x_y.setElementValue(1, x_y.getElement(1) / c); x_x.setElementValue(2, x_x.getElement(2) / c); x_y.setElementValue(2, x_y.getElement(2) / c); for (int i = 3; i < n; i++) { x_x.setElementValue(i, x_x.getElement(i) / Math.pow(c, 2)); x_y.setElementValue(i, x_y.getElement(i) / Math.pow(c, 2)); } // ----- pixel space coefficients a, b scaling back end } double devU = 0; double devV = 0; // Do warping // if (imageIndex == 0) { for (int y = 0; y < config.getGeometry().getDetectorHeight(); y++) { // for (int y=252; y<253; y++) { for (int x = 0; x < config.getGeometry().getDetectorWidth(); x++) { // for (int x=606; x<607; x++) { devU = x_x.getElement(0) + x_x.getElement(1) * x + x_x.getElement(2) * y; devV = x_y.getElement(0) + x_y.getElement(1) * x + x_y.getElement(2) * y; for (int i = 0; i < noBeadRegistered; i++) { rij = Math.pow(xy1[i][0] - x, 2) + Math.pow(xy1[i][1] - y, 2); if (rij > 0) { devU += x_x.getElement(i + 3) * rij * Math.log(rij); devV += x_y.getElement(i + 3) * rij * Math.log(rij); } } // devU = 0; // devV = 0; imp2.setf(x, y, (float) imp1.getInterpolatedValue(x - devU, y - devV)); // System.out.println("x, y=" + x + ", " + y + "\t" + devU + ", " + devV); // maxDevU = Math.max(maxDevU, devU); // maxDevV = Math.max(maxDevV, devV); } } // Error estimate after transformation // for (int i=0; i<= WeightBearingBeadPositionBuilder.currentBeadNo; i++){ // // if (beadMean3D[i][0] != 0 || beadMean3D[i][1] != 0 || beadMean3D[i][2] != 0){ // assume // bead 3d is registered. // // // find bead location if registered by txt: state 1 // if (beadPosition2D[imageIndex][i][2] == 1){ // // // Projected Reference // uv = compute2DCoordinates(beadMean3D[i], pMatrix); // double x = uv[0]; // double y = uv[1]; // // bead detected position in 2d // // Transform to 2D coordinates, time variant position // //beadPosition2D[imageIndex][i][0]; // //beadPosition2D[imageIndex][i][1]; // // devU = x_x.getElement(0) + x_x.getElement(1)*x + x_x.getElement(2)*y; // devV = x_y.getElement(0) + x_y.getElement(1)*x + x_y.getElement(2)*y; // for (int j=0; j<noBeadRegistered; j++){ // rij = Math.pow(xy1[j][0]-x, 2) + Math.pow(xy1[j][1]-y, 2); // if (rij > 0) { // devU += x_x.getElement(j+3)*rij*Math.log(rij); // devV += x_y.getElement(j+3)*rij*Math.log(rij); // } // } // // distanceReferenceToCurrentBead += // Math.sqrt(Math.pow(uv[0]-(beadPosition2D[imageIndex][i][0]+devU), // 2)+Math.pow(uv[1]-(beadPosition2D[imageIndex][i][1]+devV), 2)); // // } // } // } // System.out.println("Euclidean distance\t" + imageIndex + "\t" + // distanceReferenceToCurrentBead/noBeadRegistered); // } if (isDisplay) { for (int i = WeightBearingBeadPositionBuilder.currentBeadNo; i >= 0; i--) { if (beadMean3D[i][0] != 0 || beadMean3D[i][1] != 0 || beadMean3D[i][2] != 0) { // assume bead 3d is registered. uv = compute2DCoordinates(beadMean3D[i], pMatrix); imp2.setValue(2); // mean projected bead imp2.drawLine( (int) Math.round(uv[0] - 10), (int) Math.round(uv[1]), (int) Math.round(uv[0] + 10), (int) Math.round(uv[1])); imp2.drawLine( (int) Math.round(uv[0]), (int) Math.round(uv[1] - 10), (int) Math.round(uv[0]), (int) Math.round(uv[1] + 10)); } } } Grid2D result = new Grid2D((float[]) imp2.getPixels(), imp2.getWidth(), imp2.getHeight()); return result; }
public class ThinPlateSplinesBasedProjectionWarpingTool extends IndividualImageFilteringTool { /** * Warping projections using thin plate splines for marker based motion correction * * <p>http://elonen.iki.fi/code/tpsdemo/index.html, Based mostly on "Approximation Methods for * Thin Plate Spline Mappings and Principal Warps" by Gianluca Donato and Serge Belongie, 2002. * (http://cseweb.ucsd.edu/~sjb/pami_tps.pdf) * * @author Jang-Hwan Choi */ private static final long serialVersionUID = -3377571138470875648L; WeightBearingBeadPositionBuilder beadBuilder; Configuration config = Configuration.getGlobalConfiguration(); private boolean initBead = false; // display bead indication, horizontal & vertical lines private boolean isDisplay = false; private boolean isCornerIncluded = true; public ThinPlateSplinesBasedProjectionWarpingTool() { configured = true; } protected void initializeBead() { if (!initBead) { System.out.println("Read in initial bead positions."); beadBuilder = new WeightBearingBeadPositionBuilder(); beadBuilder.readInitialBeadPositionFromFile(); beadBuilder.estimateBeadMeanPositionIn3D(); initBead = true; } } @Override public Grid2D applyToolToImage(Grid2D imageProcessor) { FloatProcessor imp = new FloatProcessor(imageProcessor.getWidth(), imageProcessor.getHeight()); imp.setPixels(imageProcessor.getBuffer()); if (!initBead) initializeBead(); ImageProcessor imp1 = imp.duplicate(); // original double[][] beadMean3D = config.getBeadMeanPosition3D(); // [beadNo][x,y,z] double[] uv = new double[1]; SimpleMatrix pMatrix = config.getGeometry().getProjectionMatrix(imageIndex).computeP(); // [projection #][bead #][u, v, state[0: initial, 1: registered, 2: updated by hough searching]] double[][][] beadPosition2D = config.getBeadPosition2D(); int noBeadRegistered = 0; double[][] xy1 = new double[WeightBearingBeadPositionBuilder.beadNo][2]; // original double[][] xy2 = new double[WeightBearingBeadPositionBuilder.beadNo] [2]; // warped (mapped to the mean), control points, reference double[][] xy1_hat = new double[WeightBearingBeadPositionBuilder.beadNo][2]; // original double[][] xy2_hat = new double[WeightBearingBeadPositionBuilder.beadNo][2]; // original // double distanceReferenceToCurrentBead = 0; for (int i = WeightBearingBeadPositionBuilder.currentBeadNo; i >= 0; i--) { if (beadMean3D[i][0] != 0 || beadMean3D[i][1] != 0 || beadMean3D[i][2] != 0) { // assume bead 3d is registered. uv = compute2DCoordinates(beadMean3D[i], pMatrix); // find bead location if registered by txt: state 1 if (beadPosition2D[imageIndex][i][2] == 1) { noBeadRegistered++; if (isDisplay) { imp1.setValue(2); imp1.drawLine( (int) Math.round(beadPosition2D[imageIndex][i][0] - 10), (int) Math.round(beadPosition2D[imageIndex][i][1] - 10), (int) Math.round(beadPosition2D[imageIndex][i][0] + 10), (int) Math.round(beadPosition2D[imageIndex][i][1] + 10)); imp1.drawLine( (int) Math.round(beadPosition2D[imageIndex][i][0] - 10), (int) Math.round(beadPosition2D[imageIndex][i][1] + 10), (int) Math.round(beadPosition2D[imageIndex][i][0] + 10), (int) Math.round(beadPosition2D[imageIndex][i][1] - 10)); imp1.drawString( "Bead " + i + " (state:" + (int) beadPosition2D[imageIndex][i][2] + ")", (int) beadPosition2D[imageIndex][i][0], (int) beadPosition2D[imageIndex][i][1] - 10); } xy1[noBeadRegistered - 1][0] = beadPosition2D[imageIndex][i][0]; xy1[noBeadRegistered - 1][1] = beadPosition2D[imageIndex][i][1]; xy2[noBeadRegistered - 1][0] = uv[0]; xy2[noBeadRegistered - 1][1] = uv[1]; } else if (imageIndex != 0 && imageIndex != config.getGeometry().getNumProjectionMatrices() - 1) { if (beadPosition2D[imageIndex - 1][i][2] == 1 && beadPosition2D[imageIndex + 1][i][2] == 1) { noBeadRegistered++; double xMean = (beadPosition2D[imageIndex - 1][i][0] + beadPosition2D[imageIndex - 1][i][0]) / 2; double yMean = (beadPosition2D[imageIndex + 1][i][1] + beadPosition2D[imageIndex + 1][i][1]) / 2; if (isDisplay) { imp1.setValue(2); imp1.drawLine( (int) Math.round(xMean - 10), (int) Math.round(yMean - 10), (int) Math.round(xMean + 10), (int) Math.round(yMean + 10)); imp1.drawLine( (int) Math.round(xMean - 10), (int) Math.round(yMean + 10), (int) Math.round(xMean + 10), (int) Math.round(yMean - 10)); imp1.drawString("Bead " + i + " (state:" + "M)", (int) xMean, (int) yMean - 10); } xy1[noBeadRegistered - 1][0] = xMean; xy1[noBeadRegistered - 1][1] = yMean; xy2[noBeadRegistered - 1][0] = uv[0]; xy2[noBeadRegistered - 1][1] = uv[1]; } } // mean projected bead // imp1.drawLine((int) Math.round(uv[0]-10), (int) Math.round(uv[1]), (int) // Math.round(uv[0]+10), (int) Math.round(uv[1])); // imp1.drawLine((int) Math.round(uv[0]), (int) Math.round(uv[1]-10), (int) // Math.round(uv[0]), (int) Math.round(uv[1]+10)); } } if (isDisplay) { for (int x = 0; x < config.getGeometry().getDetectorWidth(); x += 50) imp1.drawLine(x, 0, x, config.getGeometry().getDetectorHeight()); for (int y = 0; y < config.getGeometry().getDetectorHeight(); y += 50) imp1.drawLine(0, y, config.getGeometry().getDetectorWidth(), y); } if (isCornerIncluded) { xy1[noBeadRegistered + 0][0] = 0; xy1[noBeadRegistered + 0][1] = 0; xy2[noBeadRegistered + 0][0] = 0; xy2[noBeadRegistered + 0][1] = 0; xy1[noBeadRegistered + 1][0] = 0; xy1[noBeadRegistered + 1][1] = config.getGeometry().getDetectorHeight(); xy2[noBeadRegistered + 1][0] = 0; xy2[noBeadRegistered + 1][1] = config.getGeometry().getDetectorHeight(); xy1[noBeadRegistered + 2][0] = config.getGeometry().getDetectorWidth(); xy1[noBeadRegistered + 2][1] = 0; xy2[noBeadRegistered + 2][0] = config.getGeometry().getDetectorWidth(); xy2[noBeadRegistered + 2][1] = 0; xy1[noBeadRegistered + 3][0] = config.getGeometry().getDetectorWidth(); xy1[noBeadRegistered + 3][1] = config.getGeometry().getDetectorHeight(); xy2[noBeadRegistered + 3][0] = config.getGeometry().getDetectorWidth(); xy2[noBeadRegistered + 3][1] = config.getGeometry().getDetectorHeight(); noBeadRegistered = noBeadRegistered + 4; } boolean fScaling = true; double minX = Double.MAX_VALUE; double maxX = 0; double minY = Double.MAX_VALUE; double maxY = 0; double c = 0; if (fScaling) { // ----- scaling to reduce condition # of A matrix for (int i = 0; i < noBeadRegistered; i++) { minX = Math.min(minX, xy1[i][0]); maxX = Math.max(maxX, xy1[i][0]); minY = Math.min(minY, xy1[i][1]); maxY = Math.max(maxY, xy1[i][1]); } c = Math.max(maxX - minX, maxY - minY); for (int i = 0; i < noBeadRegistered; i++) { xy1_hat[i][0] = (xy1[i][0] - minX) / c; xy1_hat[i][1] = (xy1[i][1] - minY) / c; xy2_hat[i][0] = (xy2[i][0] - minX) / c; xy2_hat[i][1] = (xy2[i][1] - minY) / c; } } else { xy1_hat = xy1; xy2_hat = xy2; } ImageProcessor imp2 = imp1.duplicate(); // warped /* * A*x = b * Matrix A = (n + 3) * (n + 3); * n (noBeadRegistered + 4): # of control points + 4 corner points (assume corner points are static) */ int n = noBeadRegistered + 3; SimpleMatrix A = new SimpleMatrix(n, n); SimpleVector x_x = new SimpleVector(n); SimpleVector x_y = new SimpleVector(n); SimpleVector b_x = new SimpleVector(n); SimpleVector b_y = new SimpleVector(n); double rij = 0; double valA = 0; double valb_x = 0; double valb_y = 0; // Matrix L formation // alpha: mean of distances between control points' xy-projections) is a constant only present // on the diagonal of K // lambda: TPS smoothing regularization coefficient double alpha = 0.0; double lambda = 1.6; // 1.6 for (int i = 0; i < noBeadRegistered; i++) { // i= # of row for (int j = i; j < noBeadRegistered; j++) { // j= # of column alpha += Math.sqrt( Math.pow(xy2_hat[i][0] - xy2_hat[j][0], 2) + Math.pow(xy2_hat[i][1] - xy2_hat[j][1], 2)); } } alpha = alpha / Math.pow(noBeadRegistered, 2); for (int i = 0; i < n; i++) { // i= # of row for (int j = i; j < n; j++) { // j= # of column if (i < 3 && j < 3) valA = 0; else if (i >= 3 && j >= 3 && i == j) { valA = Math.pow(alpha, 2) * lambda; // valA = lambda; if (imageIndex < 10) System.out.println("Regularization = " + valA + ", lambda= " + lambda); } else if (i == 0 && j >= 0) valA = 1; else if (i == 1 && j >= 3) valA = xy1_hat[j - 3][0]; else if (i == 2 && j >= 3) valA = xy1_hat[j - 3][1]; else { rij = Math.pow(xy1_hat[j - 3][0] - xy1_hat[i - 3][0], 2) + Math.pow(xy1_hat[j - 3][1] - xy1_hat[i - 3][1], 2); if (rij == 0) valA = 0; else valA = rij * Math.log(rij); } A.setElementValue(i, j, valA); A.setElementValue(j, i, valA); } if (i < 3) { valb_x = 0; valb_y = 0; } else { // valb_x = xy2_hat[i-3][0]-xy1_hat[i-3][0]; // valb_y = xy2_hat[i-3][1]-xy1_hat[i-3][1]; valb_x = xy2[i - 3][0] - xy1[i - 3][0]; valb_y = xy2[i - 3][1] - xy1[i - 3][1]; // if (imageIndex > 150 && imageIndex < 170) // System.out.println("Idx" + imageIndex + ",Elevation" + (i-3) + ": " + valb_x + "---" // + valb_y); } b_x.setElementValue(i, valb_x); b_y.setElementValue(i, valb_y); } // System.out.println("A condition number=" + A.conditionNumber(MatrixNormType.MAT_NORM_L1)); // System.out.println("A condition number=" + A.conditionNumber(MatrixNormType.MAT_NORM_LINF)); x_x = Solvers.solveLinearSysytemOfEquations(A, b_x); x_y = Solvers.solveLinearSysytemOfEquations(A, b_y); if (fScaling) { // ----- pixel space coefficients a, b scaling back double tmpA0 = x_x.getElement(0) - x_x.getElement(1) * (minX / c) - x_x.getElement(2) * (minY / c); for (int j = 0; j < noBeadRegistered; j++) { tmpA0 -= Math.log(c) * 2 * x_x.getElement(j + 3) * (Math.pow(xy1_hat[j][0], 2) + Math.pow(xy1_hat[j][1], 2)); } x_x.setElementValue(0, tmpA0); tmpA0 = x_y.getElement(0) - x_y.getElement(1) * (minX / c) - x_y.getElement(2) * (minY / c); for (int j = 0; j < noBeadRegistered; j++) { tmpA0 -= Math.log(c) * 2 * x_y.getElement(j + 3) * (Math.pow(xy1_hat[j][0], 2) + Math.pow(xy1_hat[j][1], 2)); } x_y.setElementValue(0, tmpA0); x_x.setElementValue(1, x_x.getElement(1) / c); x_y.setElementValue(1, x_y.getElement(1) / c); x_x.setElementValue(2, x_x.getElement(2) / c); x_y.setElementValue(2, x_y.getElement(2) / c); for (int i = 3; i < n; i++) { x_x.setElementValue(i, x_x.getElement(i) / Math.pow(c, 2)); x_y.setElementValue(i, x_y.getElement(i) / Math.pow(c, 2)); } // ----- pixel space coefficients a, b scaling back end } double devU = 0; double devV = 0; // Do warping // if (imageIndex == 0) { for (int y = 0; y < config.getGeometry().getDetectorHeight(); y++) { // for (int y=252; y<253; y++) { for (int x = 0; x < config.getGeometry().getDetectorWidth(); x++) { // for (int x=606; x<607; x++) { devU = x_x.getElement(0) + x_x.getElement(1) * x + x_x.getElement(2) * y; devV = x_y.getElement(0) + x_y.getElement(1) * x + x_y.getElement(2) * y; for (int i = 0; i < noBeadRegistered; i++) { rij = Math.pow(xy1[i][0] - x, 2) + Math.pow(xy1[i][1] - y, 2); if (rij > 0) { devU += x_x.getElement(i + 3) * rij * Math.log(rij); devV += x_y.getElement(i + 3) * rij * Math.log(rij); } } // devU = 0; // devV = 0; imp2.setf(x, y, (float) imp1.getInterpolatedValue(x - devU, y - devV)); // System.out.println("x, y=" + x + ", " + y + "\t" + devU + ", " + devV); // maxDevU = Math.max(maxDevU, devU); // maxDevV = Math.max(maxDevV, devV); } } // Error estimate after transformation // for (int i=0; i<= WeightBearingBeadPositionBuilder.currentBeadNo; i++){ // // if (beadMean3D[i][0] != 0 || beadMean3D[i][1] != 0 || beadMean3D[i][2] != 0){ // assume // bead 3d is registered. // // // find bead location if registered by txt: state 1 // if (beadPosition2D[imageIndex][i][2] == 1){ // // // Projected Reference // uv = compute2DCoordinates(beadMean3D[i], pMatrix); // double x = uv[0]; // double y = uv[1]; // // bead detected position in 2d // // Transform to 2D coordinates, time variant position // //beadPosition2D[imageIndex][i][0]; // //beadPosition2D[imageIndex][i][1]; // // devU = x_x.getElement(0) + x_x.getElement(1)*x + x_x.getElement(2)*y; // devV = x_y.getElement(0) + x_y.getElement(1)*x + x_y.getElement(2)*y; // for (int j=0; j<noBeadRegistered; j++){ // rij = Math.pow(xy1[j][0]-x, 2) + Math.pow(xy1[j][1]-y, 2); // if (rij > 0) { // devU += x_x.getElement(j+3)*rij*Math.log(rij); // devV += x_y.getElement(j+3)*rij*Math.log(rij); // } // } // // distanceReferenceToCurrentBead += // Math.sqrt(Math.pow(uv[0]-(beadPosition2D[imageIndex][i][0]+devU), // 2)+Math.pow(uv[1]-(beadPosition2D[imageIndex][i][1]+devV), 2)); // // } // } // } // System.out.println("Euclidean distance\t" + imageIndex + "\t" + // distanceReferenceToCurrentBead/noBeadRegistered); // } if (isDisplay) { for (int i = WeightBearingBeadPositionBuilder.currentBeadNo; i >= 0; i--) { if (beadMean3D[i][0] != 0 || beadMean3D[i][1] != 0 || beadMean3D[i][2] != 0) { // assume bead 3d is registered. uv = compute2DCoordinates(beadMean3D[i], pMatrix); imp2.setValue(2); // mean projected bead imp2.drawLine( (int) Math.round(uv[0] - 10), (int) Math.round(uv[1]), (int) Math.round(uv[0] + 10), (int) Math.round(uv[1])); imp2.drawLine( (int) Math.round(uv[0]), (int) Math.round(uv[1] - 10), (int) Math.round(uv[0]), (int) Math.round(uv[1] + 10)); } } } Grid2D result = new Grid2D((float[]) imp2.getPixels(), imp2.getWidth(), imp2.getHeight()); return result; } private double[] compute2DCoordinates(double[] point3D, SimpleMatrix pMatrix) { // Compute coordinates in projection data. SimpleVector homogeneousPoint = SimpleOperators.multiply(pMatrix, new SimpleVector(point3D[0], point3D[1], point3D[2], 1)); // Transform to 2D coordinates double coordU = homogeneousPoint.getElement(0) / homogeneousPoint.getElement(2); double coordV = homogeneousPoint.getElement(1) / homogeneousPoint.getElement(2); // double pxlSize = config.getGeometry().getPixelDimensionX(); return new double[] {coordU, coordV}; } @Override public IndividualImageFilteringTool clone() { IndividualImageFilteringTool clone = new ThinPlateSplinesBasedProjectionWarpingTool(); clone.configured = configured; return clone; } @Override public String getToolName() { return "Projection Warping Using Thin Plate Splines"; } @Override public void configure() throws Exception { setConfigured(true); } @Override public boolean isDeviceDependent() { return true; } @Override public String getBibtexCitation() { return "@article{Bookstein89-PWT,\n" + " author={Bookstein FL},\n" + " title={Principal warps: Thin-plate splines and the decomposition of deformations},\n" + " journal={IEEE Transactions on Pattern Analysis and Machine Intelligence},\n" + " volume={11},\n" + " number={6},\n" + " pages={568-585},\n" + " year={1989}\n" + "}"; } @Override public String getMedlineCitation() { return "Bookstein FL. Principal warps: Thin-plate splines and the decomposition of deformations. IEEE Transactions on Pattern Analysis and Machine Intelligence 11(6):568-585, 1989."; } }
protected void init() { if (!initialized) { largeVolumeMode = false; int reconDimensionX = getGeometry().getReconDimensionX(); int reconDimensionY = getGeometry().getReconDimensionY(); int reconDimensionZ = getGeometry().getReconDimensionZ(); projections = new ImageGridBuffer(); projectionsAvailable = new ArrayList<Integer>(); projectionsDone = new ArrayList<Integer>(); // Initialize the JCudaDriver. Note that this has to be done from // the same thread that will later use the JCudaDriver API. JCudaDriver.setExceptionsEnabled(true); JCudaDriver.cuInit(0); CUdevice dev = CUDAUtil.getBestDevice(); cuCtx = new CUcontext(); JCudaDriver.cuCtxCreate(cuCtx, 0, dev); // check space on device: int[] memory = new int[1]; int[] total = new int[1]; JCudaDriver.cuDeviceTotalMem(memory, dev); JCudaDriver.cuMemGetInfo(memory, total); int availableMemory = (int) (CUDAUtil.correctMemoryValue(memory[0]) / ((long) 1024 * 1024)); int requiredMemory = (int) (((((double) reconDimensionX) * reconDimensionY * ((double) reconDimensionZ) * Sizeof.FLOAT) + (((double) Configuration.getGlobalConfiguration() .getGeometry() .getDetectorHeight()) * Configuration.getGlobalConfiguration().getGeometry().getDetectorWidth() * Sizeof.FLOAT)) / (1024.0 * 1024)); if (debug) { System.out.println("Total available Memory on CUDA card:" + availableMemory); System.out.println("Required Memory on CUDA card:" + requiredMemory); } if (requiredMemory > availableMemory) { nSteps = CUDAUtil.iDivUp(requiredMemory, (int) (availableMemory)); if (debug) System.out.println("Switching to large volume mode with nSteps = " + nSteps); largeVolumeMode = true; } if (debug) { CUdevprop prop = new CUdevprop(); JCudaDriver.cuDeviceGetProperties(prop, dev); System.out.println(prop.toFormattedString()); } // Load the CUBIN file containing the kernel module = new CUmodule(); JCudaDriver.cuModuleLoad(module, "backprojectWithCuda.ptx"); // Obtain a function pointer to the kernel function. This function // will later be called. // function = new CUfunction(); JCudaDriver.cuModuleGetFunction(function, module, "_Z17backprojectKernelPfiiffffff"); // create the reconstruction volume; int memorysize = reconDimensionX * reconDimensionY * reconDimensionZ * Sizeof.FLOAT; if (largeVolumeMode) { subVolumeZ = CUDAUtil.iDivUp(reconDimensionZ, nSteps); if (debug) System.out.println("SubVolumeZ: " + subVolumeZ); h_volume = new float[reconDimensionX * reconDimensionY * subVolumeZ]; memorysize = reconDimensionX * reconDimensionY * subVolumeZ * Sizeof.FLOAT; if (debug) System.out.println("Memory: " + memorysize); } else { h_volume = new float[reconDimensionX * reconDimensionY * reconDimensionZ]; } // copy volume to device volumePointer = new CUdeviceptr(); JCudaDriver.cuMemAlloc(volumePointer, memorysize); JCudaDriver.cuMemcpyHtoD(volumePointer, Pointer.to(h_volume), memorysize); // compute adapted volume size // volume size in x = multiple of bpBlockSize[0] // volume size in y = multiple of bpBlockSize[1] int adaptedVolSize[] = new int[3]; if ((reconDimensionX % bpBlockSize[0]) == 0) { adaptedVolSize[0] = reconDimensionX; } else { adaptedVolSize[0] = ((reconDimensionX / bpBlockSize[0]) + 1) * bpBlockSize[0]; } if ((reconDimensionY % bpBlockSize[1]) == 0) { adaptedVolSize[1] = reconDimensionY; } else { adaptedVolSize[1] = ((reconDimensionY / bpBlockSize[1]) + 1) * bpBlockSize[1]; } adaptedVolSize[2] = reconDimensionZ; int volStrideHost[] = new int[2]; // compute volstride and copy it to constant memory volStrideHost[0] = adaptedVolSize[0]; volStrideHost[1] = adaptedVolSize[0] * adaptedVolSize[1]; volStride = new CUdeviceptr(); JCudaDriver.cuModuleGetGlobal(volStride, new int[1], module, "gVolStride"); JCudaDriver.cuMemcpyHtoD(volStride, Pointer.to(volStrideHost), Sizeof.INT * 2); // Calculate new grid size gridSize = new dim3( CUDAUtil.iDivUp(adaptedVolSize[0], bpBlockSize[0]), CUDAUtil.iDivUp(adaptedVolSize[1], bpBlockSize[1]), adaptedVolSize[2]); // Obtain the global pointer to the view matrix from // the module projectionMatrix = new CUdeviceptr(); JCudaDriver.cuModuleGetGlobal(projectionMatrix, new int[1], module, "gProjMatrix"); initialized = true; } }