@Override public void putLineFloat(float[] line, int k, int xdir) { final int width = ip.getWidth(); final int height = ip.getHeight(); switch (xdir) { case Ox: { if (debug) System.out.println("puting line in Ox"); final int lineno = height; int offset = k * width; int z = offset / (width * height); if (z >= 0 && z < lineno) { Object aux = ip.getPixels(); try { System.arraycopy(line, 0, aux, offset, width); // System.out.println(":"+(offset )); } catch (Exception e) { System.out.println("offset" + (offset)); e.printStackTrace(); } } break; } case Oy: { if (debug) System.out.println("puting line in Oy"); final int lineno = width; k = k % width; if (k >= 0 && k < lineno) { try { for (int y = 0; y < height; y++) { ip.setf(k, y, line[y]); // System.out.print( "("+ k +" " +y +"),"); } } catch (Exception e) { // System.out.println("k "+ k ); e.printStackTrace(); } } break; } } }
/** * Assigns the data values of an {@link ImagePlus} from a paired {@link Dataset}. Assumes the * Dataset and ImagePlus are not directly mapped. It is possible that multiple modern ImageJ axes * are encoded as a single set of channels in the ImagePlus. Sets values via {@link * ImageProcessor} ::setf(). Some special case code is in place to assure that BitType images go * to legacy ImageJ as 0/255 value images. Does not change the ImagePlus' metadata. */ @Override public void updateLegacyImage(final Dataset ds, final ImagePlus imp) { final RealType<?> type = ds.getType(); final boolean signed16BitData = type instanceof ShortType; final boolean bitData = type instanceof BitType; final RandomAccess<? extends RealType<?>> accessor = ds.getImgPlus().randomAccess(); final long[] dims = ds.getDims(); final AxisType[] axes = ds.getAxes(); final int xIndex = ds.getAxisIndex(Axes.X); final int yIndex = ds.getAxisIndex(Axes.Y); final int zIndex = ds.getAxisIndex(Axes.Z); final int tIndex = ds.getAxisIndex(Axes.TIME); final int xSize = imp.getWidth(); final int ySize = imp.getHeight(); final int zSize = imp.getNSlices(); final int tSize = imp.getNFrames(); final int cSize = imp.getNChannels(); final ImageStack stack = imp.getStack(); int planeNum = 1; final long[] pos = new long[dims.length]; for (int t = 0; t < tSize; t++) { if (tIndex >= 0) pos[tIndex] = t; for (int z = 0; z < zSize; z++) { if (zIndex >= 0) pos[zIndex] = z; for (int c = 0; c < cSize; c++) { LegacyUtils.fillChannelIndices(dims, axes, c, pos); final ImageProcessor proc = stack.getProcessor(planeNum++); for (int x = 0; x < xSize; x++) { if (xIndex >= 0) pos[xIndex] = x; for (int y = 0; y < ySize; y++) { if (yIndex >= 0) pos[yIndex] = y; accessor.setPosition(pos); double value = accessor.get().getRealDouble(); if (signed16BitData) value += 32768.0; else if (bitData) if (value > 0) value = 255; proc.setf(x, y, (float) value); } } } } } }
public void run(ImageProcessor ip) { int w = ip.getWidth(); // Get width of image int h = ip.getHeight(); // Get height of image /** * ------------------------------------------------------------------ BEGIN PRELIMINARY STEPS * ------------------------------------------------------------------* */ /** * ----------------------------------- BEGIN: CREATE IMAGES THAT WILL BE USED IN COMPUTATIONS * -----------------------------------* */ // Create the smoothed image to be used for the different edge images ImageProcessor Smoothed_Ip_xf = new FloatProcessor(w, h); ImageProcessor Smoothed_Ip_yf = new FloatProcessor(w, h); ImageProcessor Smoothed_Ip_45f = new FloatProcessor(w, h); ImageProcessor Smoothed_Ip_135f = new FloatProcessor(w, h); // Create the edge image detecting vertical edges ImageProcessor G_xf_Ip = new FloatProcessor(w, h); // Create the edge image detecting horizontal edges ImageProcessor G_yf_Ip = new FloatProcessor(w, h); // Create the edge image detecting 135 degree edges ImageProcessor G_45f_Ip = new FloatProcessor(w, h); // Create the edge image detecting 45 degree edges ImageProcessor G_135f_Ip = new FloatProcessor(w, h); // Create the gradient magnitude image ImageProcessor GMag_Ip = new ByteProcessor(w, h); // Byte version ImageProcessor GMagf_Ip = new FloatProcessor(w, h); // Floating point version // Create the gradient direction image ImageProcessor GDir_Ip = new ByteProcessor(w, h); // Byte version ImageProcessor GDirf_Ip = new FloatProcessor(w, h); // Floating point version // Create the edge image (output from non-maximal suppression) ImageProcessor Edge_Ip = new ByteProcessor(w, h); // Byte Version Edge_Ip.setValue(0); // 0 = Black Edge_Ip.fill(); // Fill Edge_Ip all black ImageProcessor Copy_Edge_Ip = new ByteProcessor(w, h); // Byte Version Copy_Edge_Ip.setValue(0); // 0 = Black Copy_Edge_Ip.fill(); // Fill Edge_Ip all black ImageProcessor Edgef_Ip = new FloatProcessor(w, h); // Floating Point version Edgef_Ip.setValue(0); // 0 = Black Edgef_Ip.fill(); // Fill Edge_Ip all black ImageProcessor Copy_Edgef_Ip = new FloatProcessor(w, h); // Floating Point version Copy_Edgef_Ip.setValue(0); // 0 = Black Copy_Edgef_Ip.fill(); // Fill Edge_Ip all black // Create the Threshold with Hysteresis image ImageProcessor Threshold_Ip = new ByteProcessor(w, h); Threshold_Ip.setValue(0); // 0 = Black Threshold_Ip.fill(); // Fill Edge_Ip all black /** * ----------------------------------- END: CREATE IMAGES THAT WILL BE USED IN COMPUTATIONS * -----------------------------------* */ /** * ----------------------------------------------------- BEGIN: USER INPUT * -----------------------------------------------------* */ double STDDev = 0, TLow = 0, THigh = 0; // Declare and initialize variables for the standard deviation, low threshold, and // high threshold int Size = 0; // Initialize size of Gaussian Filter boolean EdgeStrengthImage; // specifies whether edge strength image should be shown GenericDialog gd = new GenericDialog("User Inputs"); gd.addNumericField( "Size of Gaussian Filter (Odd Integer)", Size, 0); // Field for Size of Gaussian Filter gd.addNumericField("Standard Deviation", STDDev, 0); // Field for Standard Deviation gd.addNumericField("Low Threshold (1 - 255)", TLow, 0); // Field for Low Threshold gd.addNumericField("High Threshold (1 - 255)", THigh, 0); // Field for High Threshold gd.showDialog(); if (gd.wasCanceled()) { return; } else { Size = (int) gd .getNextNumber(); // Set Size variable from user input. This allows the user to // set the size of the Gaussian Filter STDDev = gd.getNextNumber(); // Set STDDev variable from user input TLow = gd.getNextNumber(); // Set TLow variable from user input THigh = gd.getNextNumber(); // Set THigh variable from user input } /** * ----------------------------------------------------- END: USER INPUT * -----------------------------------------------------* */ /** * ------------------------------------------------------------------ END PRELIMINARY STEPS * ------------------------------------------------------------------* */ /** * ------------------------------------------------------------------ BEGIN CANNY EDGE DETECTION * ------------------------------------------------------------------* */ /** * ----------------------------------------------------- BEGIN STEP 1: NOISE REDUCTION VIA * GAUSSIAN ----------------------------------------------------- * */ ImageProcessor ipf = ip.convertToFloat(); // Convert original image to floating point int SizeSquared = (int) Math.pow(Size, 2); // Square the size of Gaussian Kernel int HalfSize = (Size - 1) / 2; // Cut the size of the Gaussian Kernel almost in half float pix; // Temporary storage to be used throughout code to store pixel values float[] GaussianFilter = new float[SizeSquared]; // Initialize Gaussian Filter to be used in the convolution double[] GaussianFilterD = new double [SizeSquared]; // Initialize Gaussian Filter to be used...this filter will be composed // of numbers of type double double Constant = 1 / (2 * Math.PI * Math.pow(STDDev, 2)); // Compute 1/(2*pi*sigma^2) double ExponentDenom = 2 * Math.pow(STDDev, 2); // Compute 2*sigma^2 double Value; // Temporary storage to store the computations that will form the Gaussian Filter // FOR LOOP TO FORM GaussianFilterD for (int i = 0; i < Size; i++) { for (int j = 0; j < Size; j++) { Value = Math.exp( -1 * (Math.pow(j - HalfSize, 2) + Math.pow(i - HalfSize, 2)) / (ExponentDenom)); // Set Value = e^(-(i^2 + j^2)/(2*sigma^2)) GaussianFilterD[Size * i + j] = Constant * Value; // Place Value in GaussianFilterD } } // FOR LOOP TO FORM GaussianFilter using GaussianFilterD for (int i = 0; i < Math.pow(Size, 2); i++) { GaussianFilter[i] = (float) GaussianFilterD[i]; // Convert double values to float one by one } // CONVOLVE IMAGE WITH GAUSSIAN Convolver cv = new Convolver(); // Create the convolver cv.setNormalize(true); // Normalize the filter cv.convolve( ipf, GaussianFilter, Size, Size); // Apply the GaussianFilter using convolution on the image ipf // For loop to create 4 smoothed images to be used in detecting the 4 edges: 0 deg, 45 deg, 90 // deg, 135 deg for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { pix = ipf.getf(i, j); Smoothed_Ip_xf.setf( i, j, pix); // Smoothed image to convolve with Sobel filter in x-direction (detects vertical // edges) Smoothed_Ip_yf.setf( i, j, pix); // Smoothed image to convolve with Sobel filter in y-direction (detects horizontal // edges) Smoothed_Ip_45f.setf( i, j, pix); // Smoothed image to convolve with Sobel filter in 45 degree direction (detects // 135 degree edges) Smoothed_Ip_135f.setf( i, j, pix); // Smoothed image to convolve with Sobel filter in 135 degree direction (detects // 45 degree edges) } } /** * ----------------------------------------------------- END STEP 1: NOISE REDUCTION VIA * GAUSSIAN ----------------------------------------------------- * */ /** * ----------------------------------------------------- BEGIN STEP 2: COMPUTE GRADIENT * MAGNITUDE AND DIRECTION IMAGES ----------------------------------------------------- * */ // Sobel Filters to detect edges float[] G_x = {-1, 0, 1, -2, 0, 2, -1, 0, 1}; // Sobel operator in x direction float[] G_y = {-1, -2, -1, 0, 0, 0, 1, 2, 1}; // Sobel operator in y direction float[] G_135 = {2, 1, 0, 1, 0, -1, 0, -1, -2}; // Sobel operator in 135 degree direction float[] G_45 = {0, 1, 2, -1, 0, 1, -2, -1, 0}; // Sobel operator in 45 degree direction // CONVOLVE IMAGE USING SOBEL FILTERS cv.convolve( Smoothed_Ip_xf, G_x, 3, 3); // Apply the Sobel filter in x-direction using convolution on the smoothed image cv.convolve( Smoothed_Ip_yf, G_y, 3, 3); // Apply the Sobel filter in y-direction using convolution on the smoothed image cv.convolve( Smoothed_Ip_45f, G_45, 3, 3); // Apply the Sobel filter in 45 degree direction using convolution on the smoothed image cv.convolve( Smoothed_Ip_135f, G_135, 3, 3); // Apply the Sobel filter in 135 degree direction using convolution on the smoothed // image // For loop to define the 4 floating point images G_xf_Ip, G_yf_Ip, G_45f_Ip, G_135f_Ip for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { pix = Smoothed_Ip_xf.getf(i, j); G_xf_Ip.setf(i, j, pix); pix = Smoothed_Ip_yf.getf(i, j); G_yf_Ip.setf(i, j, pix); pix = Smoothed_Ip_45f.getf(i, j); G_45f_Ip.setf(i, j, pix); pix = Smoothed_Ip_135f.getf(i, j); G_135f_Ip.setf(i, j, pix); } } // COMPUTE THE GRADIENT MAGNITUDE IMAGE GMagf_Ip float pix1, pix2; // Variables to store pixel values of G_xf_Ip and G_yf_Ip for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { pix1 = G_xf_Ip.getf(i, j); // Get pixel value pix2 = G_yf_Ip.getf(i, j); // Get Pixel Value pix = (float) Math.sqrt( pix1 * pix1 + pix2 * pix2); // Take the square root of the sum of the squares of both pixel // values GMagf_Ip.setf( i, j, 255 * pix); // Place in (i,j) position of GMagf_Ip and scale by 255 to view } } // COMPUTE THE GRADIENT DIRECTION IMAGE double v1, v2, v3, v4; // Temporary storage for the abs. value of pixel vlaues int pixi; // Temporary storage for pixel values double[][] GDir = new double[h] [w]; // Define 2D Array to store gradient direction values. Will use this during Step 3 // Non-Maximal Suppression instead of the gradient direction image // For loop to compute gradient direction image for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { // Obtain the absolute value of each pixel in the following four floating point images v1 = Math.abs(G_xf_Ip.getf(i, j)); v2 = Math.abs(G_yf_Ip.getf(i, j)); v3 = Math.abs(G_45f_Ip.getf(i, j)); v4 = Math.abs(G_135f_Ip.getf(i, j)); // If statements to find the maximal response (strongest edge direction) if (v1 > v2 && v1 > v3 && v1 > v4) // Vertical edge orientation { GDir_Ip.putPixel(i, j, 0); GDir[j][i] = 0; // 0 stands for vertical edge orientation } else if (v3 > v1 && v3 > v2 && v3 > v4) // 45 degree edge orientation { GDir_Ip.putPixel(i, j, 1); GDir[j][i] = 1; // 1 stands for 45 degree edge orientation } else if (v2 > v1 && v2 > v3 && v2 > v4) // Horizontal edge orientation { GDir_Ip.putPixel(i, j, 2); GDir[j][i] = 2; // 2 stands for horizontal edge orientation } else if (v4 > v1 && v4 > v2 && v4 > v3) // 135 degree edge orientation { GDir_Ip.putPixel(i, j, 3); GDir[j][i] = 3; // 3 stands for 135 degree edge orientation } pixi = (int) (255.0 / 3.0) * GDir_Ip.getPixel( i, j); // Scale the gradient direction image so we can actually see it GDir_Ip.putPixel( i, j, pixi); // Place pixi in the (i,j) location of GDir_Ip...we can now view the gradient // direction image } } // OUTPUT GRADIENT DIRECTION IMAGE String DirTitle = "Gradient Direction"; ImagePlus GDir_Im = new ImagePlus(DirTitle, GDir_Ip); GDir_Im.show(); // OUTPUT GRADIENT MAGNITUDE IMAGE (need to convert to ByteProcessor to view first) GMagf_Ip.resetMinAndMax(); GMag_Ip.insert(GMagf_Ip.convertToByte(true), 0, 0); String MagTitle = "Gradient Magnitude"; ImagePlus GMag_Im = new ImagePlus(MagTitle, GMag_Ip); GMag_Im.show(); /** * ----------------------------------------------------- BEGIN STEP 2: COMPUTE GRADIENT * MAGNITUDE AND DIRECTION IMAGES ----------------------------------------------------- * */ /** * ----------------------------------------------------- BEGIN STEP 3: NON-MAXIMAL SUPPRESSION * -----------------------------------------------------* */ // Ignoring boundaries for convenience float Magnitude; // Storage for magnitude double Direction; // Storage for direction // FOR LOOP TO COMPUTE NON-MAXIMAL SUPPRESSION IMAGE for (int i = 1; i < w - 1; i++) { for (int j = 1; j < h - 1; j++) { Magnitude = GMagf_Ip.getf( i, j); // Get the magnitude in the (i,j) position of the gradient magnitude image if (Magnitude != 0) // If the magnitude is non-zero then we find the direction of the edge { Direction = GDir[j][i]; // Obtain the direction float n1GradMag = 0, n2GradMag = 0; // Initialize storage for the magnitude of the 2 neighboring pixels if (Direction == 0) // If Direction is 0 get the magnitude in the columns to the left and right { n1GradMag = GMagf_Ip.getf(i - 1, j); n2GradMag = GMagf_Ip.getf(i + 1, j); } else if (Direction == 1) // If Direction is 45 degree get the magnitude in adjacent pixels { n1GradMag = GMagf_Ip.getf(i + 1, j - 1); n2GradMag = GMagf_Ip.getf(i - 1, j + 1); } else if (Direction == 2) // If Direction is 2 get the magnitude in the rows above and below { n1GradMag = GMagf_Ip.getf(i, j - 1); n2GradMag = GMagf_Ip.getf(i, j + 1); } else if (Direction == 3) // If Direction is 135 degrees get the magnitude in adjacent pixels { n1GradMag = GMagf_Ip.getf(i - 1, j - 1); n2GradMag = GMagf_Ip.getf(i + 1, j + 1); } if (Magnitude > n1GradMag && Magnitude > n2GradMag) // Check to see if the magnitude of pixel under inspection is the // largest relative to its adjacent pixels { pix = GMagf_Ip.getf(i, j); // Store magnitude in (i,j) position in pix variable Edgef_Ip.setf( i, j, pix); // Place this pixel value in the (i,j) position of Edge Image (Edge Image is // output from non-maximal suppression) Copy_Edgef_Ip.setf( i, j, pix); // Place this pixel value in the (i,j) position of Copy Edge Image (this will // be used for thresholding with hysteresis) } else { } // Else do nothing since edge image was already filled with 0's at beginning of code } else { } // Do nothing if magnitude is 0 } } Copy_Edgef_Ip.resetMinAndMax(); Copy_Edge_Ip.insert(Copy_Edgef_Ip.convertToByte(true), 0, 0); // Display edge magnitude image but we need to convert to ByteProcessor first Edgef_Ip.resetMinAndMax(); Edge_Ip.insert(Edgef_Ip.convertToByte(true), 0, 0); String cTitle = "Non-Maximal Suppression"; ImagePlus Edge_Im = new ImagePlus(cTitle, Edge_Ip); Edge_Im.show(); /** * ----------------------------------------------------- END STEP 3: NON-MAXIMAL SUPPRESSION * -----------------------------------------------------* */ /** * ----------------------------------------------------- BEGIN STEP 4: THRESHOLDING WITH * HYSTERESIS -----------------------------------------------------* */ int count = 0; // Initialize counter to be used in while loop int IterationCount = 500; // Number of iterations to perform // Scan through all pixels in the edge image and mark all edges with magnitude above the high // threshold as a true edge otherwise if the magnitude is below the low threshold // then we delete that pixel (set it to zero) for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { Magnitude = Copy_Edge_Ip.getPixel(i, j); // Obtain magnitude in edge image if (Magnitude > THigh) // If Magnitude is larger than the high threshold then make pixel white { Threshold_Ip.putPixel(i, j, 255); // True edge (Updates Threshold image to be output) Copy_Edge_Ip.putPixel( i, j, 255); // True edge (Updates edge image which will be used in the iterative // thresholding) } else if (Magnitude < TLow) // Else if magnitude is below the low threshold then make pixel black { Threshold_Ip.putPixel(i, j, 0); // Not an edge (Updates Threshold image to be output) Copy_Edge_Ip.putPixel( i, j, 0); // Not an edge (Updates edge image which will be used in the iterative // thresholding) } } } while (count < IterationCount) // Iterate again and again { // Ignore boundary pixels for convenience for (int i = 1; i < w - 1; i++) { for (int j = 1; j < h - 1; j++) { Magnitude = Copy_Edge_Ip.getPixel(i, j); // Obtain magnitude in edge image if (Magnitude == 255) // If we reach a true edge then we look at its 8 neighbors { // Obtain the magnitude in the 8 neighbors int n1, n2, n3, n4, n5, n6, n7, n8; n1 = Copy_Edge_Ip.getPixel(i - 1, j); n2 = Copy_Edge_Ip.getPixel(i - 1, j - 1); n3 = Copy_Edge_Ip.getPixel(i, j - 1); n4 = Copy_Edge_Ip.getPixel(i + 1, j - 1); n5 = Copy_Edge_Ip.getPixel(i + 1, j); n6 = Copy_Edge_Ip.getPixel(i + 1, j + 1); n7 = Copy_Edge_Ip.getPixel(i, j + 1); n8 = Copy_Edge_Ip.getPixel(i - 1, j + 1); if (n1 >= TLow) // If n1 is greater than or equal to the low threshold then we mark it as // an edge { Copy_Edge_Ip.putPixel(i - 1, j, 255); // Update edge image Threshold_Ip.putPixel( i - 1, j, 255); // Update threshold image (This is the output image from thresholding with // hysteresis) } if (n2 >= TLow) // If n2 is greater than or equal to the low threshold then we mark it as // an edge { Copy_Edge_Ip.putPixel(i - 1, j - 1, 255); // Update edge image Threshold_Ip.putPixel( i - 1, j - 1, 255); // Update threshold image (This is the output image from thresholding with // hysteresis) } if (n3 >= TLow) // If n3 is greater than or equal to the low threshold then we mark it as // an edge { Copy_Edge_Ip.putPixel(i, j - 1, 255); // Update edge image Threshold_Ip.putPixel( i, j - 1, 255); // Update threshold image (This is the output image from thresholding with // hysteresis) } if (n4 >= TLow) // If n4 is greater than or equal to the low threshold then we mark it as // an edge { Copy_Edge_Ip.putPixel(i + 1, j - 1, 255); // Update edge image Threshold_Ip.putPixel( i + 1, j - 1, 255); // Update threshold image (This is the output image from thresholding with // hysteresis) } if (n5 >= TLow) // If n5 is greater than or equal to the low threshold then we mark it as // an edge { Copy_Edge_Ip.putPixel(i + 1, j, 255); // Update edge image Threshold_Ip.putPixel( i + 1, j, 255); // Update threshold image (This is the output image from thresholding with // hysteresis) } if (n6 >= TLow) // If n6 is greater than or equal to the low threshold then we mark it as // an edge { Copy_Edge_Ip.putPixel(i + 1, j + 1, 255); // Update edge image Threshold_Ip.putPixel( i + 1, j + 1, 255); // Update threshold image (This is the output image from thresholding with // hysteresis) } if (n7 >= TLow) // If n7 is greater than or equal to the low threshold then we mark it as // an edge { Copy_Edge_Ip.putPixel(i, j + 1, 255); // Update edge image Threshold_Ip.putPixel( i, j + 1, 255); // Update threshold image (This is the output image from thresholding with // hysteresis) } if (n8 >= TLow) // If n8 is greater than or equal to the low threshold then we mark it as // an edge { Copy_Edge_Ip.putPixel(i - 1, j + 1, 255); // Update edge image Threshold_Ip.putPixel( i - 1, j + 1, 255); // Update threshold image (This is the output image from thresholding with // hysteresis) } } } } count++; // Update counter and continue iterations } // Display the threshold with hysteresis image. String ThreshTitle = "Threshold with Hysteresis"; ImagePlus Threshold_Im = new ImagePlus(ThreshTitle, Threshold_Ip); Threshold_Im.show(); /** * ----------------------------------------------------- END STEP 4: THRESHOLDING WITH * HYSTERESIS -----------------------------------------------------* */ /** * ------------------------------------------------------------------ END CANNY EDGE DETECTION * ------------------------------------------------------------------* */ }
@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; }
/** * @param ip * @param v */ public static void run(final ImageProcessor ip, final float v) { final int w = ip.getWidth(); final int h = ip.getHeight(); final int wh = w * h; final ImageProcessor ipTarget = ip.duplicate(); int numSaturatedPixels = 0; do { numSaturatedPixels = 0; for (int i = 0; i < wh; ++i) if (ip.getf(i) == v) { ++numSaturatedPixels; final int y = i / w; final int x = i % w; float s = 0; float n = 0; if (y > 0) { if (x > 0) { final float tl = ip.getf(x - 1, y - 1); if (tl != v) { s += 0.5f * tl; n += 0.5f; } } final float t = ip.getf(x, y - 1); if (t != v) { s += t; n += 1; } if (x < w - 1) { final float tr = ip.getf(x + 1, y - 1); if (tr != v) { s += 0.5f * tr; n += 0.5f; } } } if (x > 0) { final float l = ip.getf(x - 1, y); if (l != v) { s += l; n += 1; } } if (x < w - 1) { final float r = ip.getf(x + 1, y); if (r != v) { s += r; n += 1; } } if (y < h - 1) { if (x > 0) { final float bl = ip.getf(x - 1, y + 1); if (bl != v) { s += 0.5f * bl; n += 0.5f; } } final float b = ip.getf(x, y + 1); if (b != v) { s += b; n += 1; } if (x < w - 1) { final float br = ip.getf(x + 1, y + 1); if (br != v) { s += 0.5f * br; n += 0.5f; } } } if (n > 0) ipTarget.setf(i, s / n); } ip.setPixels(ipTarget.getPixelsCopy()); } while (numSaturatedPixels > 0); }