Example #1
0
    /**
     * constructor to create a view
     *
     * @param projection: projection image as Grid2D
     * @param radon: radon transformed and derived image as Grid2D
     * @param projMatrix: projection matrix as Projection
     */
    public View(Grid2D projection, Grid2D radon, Projection projMatrix) {

      // Initialize center matrix //
      CENTER = new SimpleMatrix(3, 4);
      CENTER.setDiagValue(new SimpleVector(1.0, 1.0, 1.0));

      // get data out of projection //
      this.projectionWidth = projection.getWidth();
      this.projectionHeight = projection.getHeight();

      // get data out of radon transformed image //
      this.radonWidth = radon.getWidth();
      this.radonHeight = radon.getHeight();
      this.projectionDiag =
          Math.sqrt(projectionWidth * projectionWidth + projectionHeight * projectionHeight);
      this.lineIncrement = radonWidth / projectionDiag;
      this.angleIncrement = radonHeight / Math.PI;

      // store radon transformed image //
      this.radon = radon;

      // get projection matrix P (3x4) //
      this.P = SimpleOperators.multiplyMatrixProd(projMatrix.getK(), CENTER);
      this.P = SimpleOperators.multiplyMatrixProd(this.P, projMatrix.getRt());

      // get source position C (nullspace of the projection) //
      DecompositionSVD decoP = new DecompositionSVD(this.P);
      this.C = decoP.getV().getCol(3);

      // normalize source vectors by last component //
      // it is important that the last component is positive to have a positive center
      // as it is defined in oriented projective geometry
      this.C = this.C.dividedBy(this.C.getElement(3));
    }
Example #2
0
  /**
   * Creates the meshes of one single phase and adds it to the ArrayList of 4D meshes.
   *
   * @param phase
   * @param parameters
   * @param info
   * @param splines
   */
  private void createPhantom(
      int phase, double[] parameters, CONRADCardiacModelConfig info, ArrayList<Mesh4D> splines) {
    String pcaFile = heartBase + "\\CardiacModel\\phase_" + phase + ".ccm";
    ActiveShapeModel asm = new ActiveShapeModel(pcaFile);
    Mesh allComp = asm.getModel(parameters);

    if (phase == 0) {
      for (int i = 0; i < info.numAnatComp; i++) {
        splines.add(new Mesh4D());
      }
    }

    int count = 0;
    for (heartComponents hc : heartComponents.values()) {
      Mesh comp = new Mesh();
      SimpleMatrix pts =
          allComp
              .getPoints()
              .getSubMatrix(info.vertexOffs[count], 0, hc.getNumVertices(), info.vertexDim);
      // rotate and translate points
      for (int i = 0; i < pts.getRows(); i++) {
        SimpleVector row = SimpleOperators.multiply(rot, pts.getRow(i));
        row.add(trans);
        pts.setRowValue(i, row);
      }
      comp.setPoints(pts);
      comp.setConnectivity(
          allComp
              .getConnectivity()
              .getSubMatrix(info.triangleOffs[count], 0, hc.getNumTriangles(), 3));
      splines.get(count).addMesh(comp);
      count++;
    }
  }
Example #3
0
  /**
   * method to calculate a mapping K from two source positions C0, C1 to a plane C0 (C1) is the
   * source position from the first (second) view
   */
  public void createMappingToEpipolarPlane() {

    // set up source matrices //
    SimpleVector C0 = this.view1.C;
    SimpleVector C1 = this.view2.C;

    // compute Pluecker coordinates //
    double L01 = C0.getElement(0) * C1.getElement(1) - C0.getElement(1) * C1.getElement(0);
    double L02 = C0.getElement(0) * C1.getElement(2) - C0.getElement(2) * C1.getElement(0);
    double L03 = C0.getElement(0) * C1.getElement(3) - C0.getElement(3) * C1.getElement(0);
    double L12 = C0.getElement(1) * C1.getElement(2) - C0.getElement(2) * C1.getElement(1);
    double L13 = C0.getElement(1) * C1.getElement(3) - C0.getElement(3) * C1.getElement(1);
    double L23 = C0.getElement(2) * C1.getElement(3) - C0.getElement(3) * C1.getElement(2);

    // construct B (6x1) //
    SimpleVector B = new SimpleVector(L01, L02, L03, L12, L13, L23);

    // compute infinity point in direction of B //
    SimpleVector N = new SimpleVector(-L03, -L13, -L23, 0);

    // compute plane E0 containing B and X0=(0,0,0,1) //
    SimpleVector E0 = SimpleOperators.getPlueckerJoin(B, new SimpleVector(0, 0, 0, 1));

    // find othonormal basis from plane normals //
    // (vectors are of 3x1)
    SimpleVector a2 = new SimpleVector(E0.getElement(0), E0.getElement(1), E0.getElement(2));
    SimpleVector a3 = new SimpleVector(N.getElement(0), N.getElement(1), N.getElement(2));
    // set vectors to unit length
    a2.normalizeL2();
    a3.normalizeL2();

    // calculate cross product to get the last basis vector //
    SimpleVector a1 = General.crossProduct(a2, a3).negated();
    // (a1 is already of unit length -> no normalization needed)

    // set up assembly matrix A (4x3) //
    SimpleMatrix A = new SimpleMatrix(4, 3);
    A.setSubColValue(0, 0, a1);
    A.setSubColValue(0, 1, a2);
    A.setSubColValue(0, 2, C0);

    // store mapping matrix K (4x3 = 4x4 * 4x3) //
    this.K = SimpleOperators.multiplyMatrixProd(SimpleOperators.getPlueckerMatrixDual(B), A);
  }
  @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);
  }
  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};
  }
Example #6
0
  /**
   * method to compute the epipolar line integrals that state the epipolar consistency conditions by
   * comparison of two views
   *
   * @param kappa_RAD: angle of epipolar plane
   * @return double[] array containing two values (one for each view's line integral)
   */
  public double[] computeEpipolarLineIntegrals(double kappa_RAD) {

    // compute points on unit-circle (3x1) //
    SimpleVector x_kappa = new SimpleVector(Math.cos(kappa_RAD), Math.sin(kappa_RAD), 1);

    // compute epipolar plane E_kappa (4x1 = 4x3 * 3x1) //
    SimpleVector E_kappa = SimpleOperators.multiply(this.K, x_kappa);

    // compute line integral out of derived radon transform //
    double value1 = view1.getValueByAlphaAndT(E_kappa);
    double value2 = view2.getValueByAlphaAndT(E_kappa);

    // both values are returned //
    return new double[] {value1, value2};
  }
Example #7
0
    /**
     * Method to calculate alpha and t as indices from the radon transformed image of a view.
     * Neccessary are the inverse projection image (as SimpleMatrix) and the epipolar plane E
     *
     * @param E: epipolar plane E as SimpleVector (4 entries)
     * @return: line integral value as double
     */
    private double getValueByAlphaAndT(SimpleVector E) {

      // compute corresponding epipolar lines //
      // (epipolar lines are of 3x1 = 3x4 * 4x1)
      SimpleVector l_kappa = SimpleOperators.multiply(this.P_Inverse.transposed(), E);

      // init the coordinate shift //
      int t_u = this.projectionWidth / 2;
      int t_v = this.projectionHeight / 2;

      // compute angle alpha and distance to origin t //
      double l0 = l_kappa.getElement(0);
      double l1 = l_kappa.getElement(1);
      double l2 = l_kappa.getElement(2);

      double alpha_kappa_RAD = Math.atan2(-l0, l1) + Math.PI / 2;

      double t_kappa = -l2 / Math.sqrt(l0 * l0 + l1 * l1);
      // correct the coordinate shift //
      t_kappa -= t_u * Math.cos(alpha_kappa_RAD) + t_v * Math.sin(alpha_kappa_RAD);

      // correct some alpha falling out of the radon window //
      if (alpha_kappa_RAD < 0) {
        alpha_kappa_RAD *= -1.0;
      } else if (alpha_kappa_RAD > Math.PI) {
        alpha_kappa_RAD = 2.0 * Math.PI - alpha_kappa_RAD;
      }

      // write back to l_kappa //
      l_kappa.setElementValue(0, Math.cos(alpha_kappa_RAD));
      l_kappa.setElementValue(1, Math.sin(alpha_kappa_RAD));
      l_kappa.setElementValue(2, -t_kappa);

      // calculate x and y coordinates for derived radon transformed image //
      double x = t_kappa * this.lineIncrement + 0.5 * this.radonWidth;
      double y = alpha_kappa_RAD * this.angleIncrement;

      // get intensity value out of radon transformed image //
      // (interpolation needed)
      return InterpolationOperators.interpolateLinear(this.radon, x, y);
    }
  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;
  }
  public void setTrajectory(
      int numProjectionMatrices,
      double sourceToAxisDistance,
      double averageAngularIncrement,
      double detectorOffsetX,
      double detectorOffsetY,
      CameraAxisDirection uDirection,
      CameraAxisDirection vDirection,
      SimpleVector rotationAxis,
      PointND rotationCenter,
      double angleFirstProjection) {
    this.projectionMatrices = new Projection[numProjectionMatrices];
    this.primaryAngles = new double[numProjectionMatrices];
    this.numProjectionMatrices = numProjectionMatrices;
    this.sourceToAxisDistance = sourceToAxisDistance;
    this.averageAngularIncrement = averageAngularIncrement;
    this.detectorOffsetU = detectorOffsetX;
    this.detectorOffsetV = detectorOffsetY;

    double cosPhi = Math.cos(General.toRadians(angleFirstProjection));
    double sinPhi = Math.sin(General.toRadians(angleFirstProjection));
    SimpleMatrix rotMat = new SimpleMatrix(3, 3);
    rotMat.setElementValue(0, 0, cosPhi);
    rotMat.setElementValue(0, 1, sinPhi);
    rotMat.setElementValue(1, 0, -sinPhi);
    rotMat.setElementValue(1, 1, cosPhi);
    rotMat.setElementValue(2, 2, 1);
    SimpleVector centerToCameraIdealAtInitialAngle =
        SimpleOperators.multiply(rotMat, new SimpleVector(sourceToAxisDistance, 0, 0));
    Plane3D trajPlane =
        new Plane3D(
            rotationAxis,
            SimpleOperators.multiplyInnerProd(rotationAxis, rotationCenter.getAbstractVector()));
    double distToPlane = trajPlane.computeDistance(new PointND(centerToCameraIdealAtInitialAngle));
    SimpleVector centerToCameraDir =
        SimpleOperators.subtract(
            SimpleOperators.add(
                rotationAxis.multipliedBy(-1 * distToPlane), centerToCameraIdealAtInitialAngle),
            rotationCenter.getAbstractVector());
    centerToCameraDir.divideBy(centerToCameraDir.normL2());
    SimpleVector centerToCameraInitialInPlane =
        centerToCameraDir.multipliedBy(sourceToAxisDistance);

    for (int i = 0; i < numProjectionMatrices; i++) {
      primaryAngles[i] = i * averageAngularIncrement + angleFirstProjection;
      // System.out.println(primaryAngles[i] + " " + averageAngularIncrement + " " +
      // this.reconDimensions[0] + " " + this.reconDimensions[1]);
      projectionMatrices[i] = new Projection();
      double rotationAngle = General.toRadians(primaryAngles[i]);
      projectionMatrices[i].setRtFromCircularTrajectory(
          rotationCenter.getAbstractVector(),
          rotationAxis,
          sourceToAxisDistance,
          centerToCameraInitialInPlane,
          uDirection,
          vDirection,
          rotationAngle);
      SimpleVector spacingUV = new SimpleVector(pixelDimensionX, pixelDimensionY);
      SimpleVector sizeUV = new SimpleVector(detectorWidth, detectorHeight);
      SimpleVector offset = new SimpleVector(detectorOffsetX, detectorOffsetY);
      projectionMatrices[i].setKFromDistancesSpacingsSizeOffset(
          sourceToDetectorDistance, spacingUV, sizeUV, offset, 1.0, 0);
    }
    this.projectionStackSize = numProjectionMatrices;
    // System.out.println("Defined geometry with SDD " +sourceToDetectorDistance);
  }
  private void visualizeKleinNishina(double energyJoule) {
    int gridWidth = 600;
    int gridHeight = 500;
    double maxAngle = 360;

    Grid2D grid = new Grid2D(gridWidth, gridHeight);

    FloatProcessor fp = new FloatProcessor(grid.getWidth(), grid.getHeight());
    fp.setPixels(grid.getBuffer());

    // find max value
    double max = 0;
    for (int i = 0; i < maxAngle; ++i) {
      double value = XRayTracerSampling.comptonAngleProbability(energyJoule, Math.toRadians(i));

      if (value > max) {
        max = value;
      }
    }

    fp.drawLine((int) 0, grid.getHeight() / 2, grid.getWidth(), grid.getHeight() / 2);
    fp.drawLine(grid.getWidth() / 2, 0, grid.getWidth() / 2, grid.getHeight());
    fp.drawOval((grid.getWidth() - grid.getHeight()) / 2, 0, grid.getHeight(), grid.getHeight());
    double lastX = 0;
    double lastY = 0;

    // draw angle distribution
    for (int i = 0; i < maxAngle; ++i) {
      double value = XRayTracerSampling.comptonAngleProbability(energyJoule, Math.toRadians(i));

      SimpleMatrix m = Rotations.createBasicZRotationMatrix(Math.toRadians(i));
      SimpleVector v = new SimpleVector(((value / max) * ((double) grid.getHeight() / 2.d)), 0, 0);

      SimpleVector r = SimpleOperators.multiply(m, v);

      double x = grid.getWidth() / 2 + r.getElement(0);
      double y = grid.getHeight() / 2 + r.getElement(1);
      if (i > 0) fp.drawLine((int) lastX, (int) lastY, (int) x, (int) y);
      lastX = x;
      lastY = y;
    }

    grid.show(
        "Normalized Klein-Nishina cross-section as a function of scatter angle ("
            + energyJoule / eV
            + "eV)");

    grid = new Grid2D(gridWidth, gridHeight);

    fp = new FloatProcessor(grid.getWidth(), grid.getHeight());
    fp.setPixels(grid.getBuffer());

    // draw histogram with rejection sampling of the klein-nishina
    // distribution
    int[] angles = new int[grid.getWidth()];
    for (int i = 0; i < numSamples; ++i) {
      double angle = Math.toDegrees(sampler.getComptonAngleTheta(energyJoule));
      int pos = (int) (angle * grid.getWidth() / 360.d);
      angles[pos] += 1;
    }
    double max2 = 0;
    for (int i = 0; i < angles.length; ++i) {
      if (angles[i] > max2) {
        max2 = angles[i];
      }
    }
    for (int i = 0; i < angles.length; ++i) {
      double x = i;
      double y = ((angles[i]) * (grid.getHeight() / (max2)));
      fp.drawLine((int) x, (int) grid.getHeight(), (int) x, grid.getHeight() - (int) y);
    }

    // draw klein-nishina probability function
    lastX = 0;
    lastY = 0;
    for (int i = 0; i < maxAngle; ++i) {
      double value = XRayTracerSampling.comptonAngleProbability(energyJoule, Math.toRadians(i));
      double x = (i * (grid.getWidth() / 360.f));
      double y = grid.getHeight() - ((value) * (grid.getHeight() / (max)));

      fp.drawLine((int) lastX, (int) lastY, (int) x, (int) y);
      lastX = x;
      lastY = y;
    }

    grid.show(
        "Energy: " + energyJoule / eV + "eV; x-axis: angle[0-360]; y-axis: probability[0-max]");
  }