/** * 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)); }
/** * method to compute the squared radon transformed and derived image for one view the derivation * is done in t-direction (distance to origin) * * @param data: Grid2D which represents the projection * @param radonSize: value to determine the size of the squared radon transformed and derived * image * @return: radon transformed image as Grid2D (its size is radonSize x radonSize) */ public static Grid2D computeRadonTrafoAndDerive(Grid2D data, int radonSize) { Grid2D radon = null; // optional: preprocessing can be done here // for example: /* float value; for (int i = 0; i < data.getWidth(); i++) { for (int j = 0; j < data.getHeight(); j++) { if (j < 10 || j > data.getHeight() - 11) { // set border to zero value = 0.0f; } else { value = (float)(-Math.log(data.getAtIndex(i, j) / 0.842f)); } data.setAtIndex(i, j, value); } } data.show("preprocessed image"); */ // * get some dimensions out of data (projection) *// int projSizeX = data.getWidth(); int projSizeY = data.getHeight(); double projectionDiag = Math.sqrt(projSizeX * projSizeX + projSizeY * projSizeY); double deltaS = projectionDiag / radonSize; double deltaTheta = Math.PI / radonSize; // * create a parallel projector in order to compute the radon transformation *// ParallelProjector2D projector = new ParallelProjector2D(Math.PI, deltaTheta, projectionDiag, deltaS); // * create radon transformation *// radon = projector.projectRayDriven(data); // for a faster GPU implementation use: (possibly not working): // radon = projector.projectRayDrivenCL(data); // * derivative by Sobel operator in t-direction *// final int size = 1024; SobelKernel1D kernel = new SobelKernel1D(size, 9); kernel.applyToGrid(radon); // * optional: save file in tiff-format *// /* FileSaver saveRadon = new FileSaver(ImageUtil.wrapGrid(radon, "")); saveRadon.saveAsTiff(); */ return radon; }
/** * 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); }