/* * #%L * Ridge Detection plugin for ImageJ * %% * Copyright (C) 2014 - 2015 Thorsten Wagner (ImageJ java plugin), 1996-1998 Carsten Steger (original C code), 1999 R. Balasubramanian (detect lines code to incorporate within GRASP) * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-2.0.html>. * #L% */ package de.biomedical_imaging.ij.steger; import org.apache.commons.lang3.mutable.MutableLong; // TODO: Auto-generated Javadoc /** * The Class Convol. */ public class Convol { /** The sqrt 2 pi inv. */ /* 1/sqrt(2*PI) */ private final double SQRT_2_PI_INV = 0.398942280401432677939946059935; /* * Functions to compute the integral, and the 0th and 1st derivative of the * Gaussian function 1/(sqrt(2*PI)*sigma)*exp(-0.5*x^2/sigma^2) */ /** * Phi 0. * * @param x * the x * @param sigma * the sigma * @return the double */ /* Integral of the Gaussian function */ private double phi0(double x, double sigma) { return Normal.getNormal(x / sigma); } /** * Phi 1. * * @param x * the x * @param sigma * the sigma * @return the double */ /* The Gaussian function */ private double phi1(double x, double sigma) { double t; t = x / sigma; return SQRT_2_PI_INV / sigma * Math.exp(-0.5 * t * t); } /** * Phi 2. * * @param x * the x * @param sigma * the sigma * @return the double */ /* First derivative of the Gaussian function */ public double phi2(double x, double sigma) { double t; t = x / sigma; return -x * SQRT_2_PI_INV / Math.pow(sigma, 3.0) * Math.exp(-0.5 * t * t); } /* * Functions to compute the one-dimensional convolution masks of the 0th, 1st, * and 2nd derivative of the Gaussian kernel for a certain smoothing level given * by sigma. The mask is allocated by the function and given as the return * value. The caller must ensure that this memory is freed. The output is * intended to be used as an array with range [-num:num]. Therefore, the caller * should add num to the return value. Examples for the calling sequence can be * found in convolve_gauss. Examples for the usage of the masks are given in * convolve_rows_gauss and convolve_cols_gauss. */ /* Gaussian smoothing mask */ /** * Compute gauss mask 0. * * @param num * the num * @param sigma * the sigma * @return the double[] */ /* * num ist eigentlich pointer - aufrufende Funkion nimmt an, dass num geändert * wird. Übergebe es deswegen als MutableDouble aus CommonsLang */ public double[] compute_gauss_mask_0(MutableLong num, double sigma) { int i, n; double limit; double[] h; limit = LinesUtil.MASK_SIZE(LinesUtil.MAX_SIZE_MASK_0, sigma); /* Error < 0.001 on each side */ n = (int) limit; h = new double[2 * n + 1]; for (i = -n + 1; i <= n - 1; i++) h[n + i] = phi0(-i + 0.5, sigma) - phi0(-i - 0.5, sigma); h[0] = 1.0 - phi0(n - 0.5, sigma); h[2 * n] = phi0(-n + 0.5, sigma); num.setValue(n); return h; } /* First derivative of Gaussian smoothing mask */ /** * Compute gauss mask 1. * * @param num * the num * @param sigma * the sigma * @return the double[] */ /* * num ist eigentlich pointer - aufrufende Funkion nimmt an, dass num geändert * wird. Übergebe es deswegen als MutableDouble aus CommonsLang */ public double[] compute_gauss_mask_1(MutableLong num, double sigma) { int i, n; double limit; double[] h; limit = LinesUtil.MASK_SIZE(LinesUtil.MAX_SIZE_MASK_1, sigma); /* Error < 0.001 on each side */ n = (int) limit; h = new double[2 * n + 1]; for (i = -n + 1; i <= n - 1; i++) h[n + i] = phi1(-i + 0.5, sigma) - phi1(-i - 0.5, sigma); h[0] = -phi1(n - 0.5, sigma); h[2 * n] = phi1(-n + 0.5, sigma); num.setValue(n); return h; } /* Second derivative of Gaussian smoothing mask */ /** * Compute gauss mask 2. * * @param num * the num * @param sigma * the sigma * @return the double[] */ /* * num ist eigentlich pointer - aufrufende Funkion nimmt an, dass num geändert * wird. Übergebe es deswegen als MutableDouble aus CommonsLang */ public double[] compute_gauss_mask_2(MutableLong num, double sigma) { int i, n; double limit; double[] h; limit = LinesUtil.MASK_SIZE(LinesUtil.MAX_SIZE_MASK_2, sigma); /* Error < 0.001 on each side */ n = (int) limit; h = new double[2 * n + 1]; for (i = -n + 1; i <= n - 1; i++) h[n + i] = phi2(-i + 0.5, sigma) - phi2(-i - 0.5, sigma); h[0] = -phi2(n - 0.5, sigma); h[2 * n] = phi2(-n + 0.5, sigma); num.setValue(n); return h; } /* * Convolve an image with the derivatives of a Gaussian smoothing kernel. Since * all of the masks are separable, this is done in two steps in the function * convolve_gauss. Firstly, the rows of the image are convolved by an * appropriate one-dimensional mask in convolve_rows_gauss, yielding an * intermediate float-image h. Then the columns of this image are convolved by * another appropriate mask in convolve_cols_gauss to yield the final result k. * At the border of the image the gray values are mirrored. */ /** * Convolve rows gauss. * * @param image * the image * @param mask * the mask * @param n * the n * @param h * the h * @param width * the width * @param height * the height */ /* Convolve the rows of an image with the derivatives of a Gaussian. */ private void convolve_rows_gauss(float[] image, double[] mask, int n, float[] h, int width, int height) { int j, r, c, l; double sum; /* Inner region */ for (r = n; r < height - n; r++) { for (c = 0; c < width; c++) { l = LinesUtil.LINCOOR(r, c, width); sum = 0.0; for (j = -n; j <= n; j++) sum += (double) (image[(l + j * width)]) * mask[(j + n)]; h[l] = (float) sum; } } /* Border regions */ for (r = 0; r < n; r++) { for (c = 0; c < width; c++) { l = LinesUtil.LINCOOR(r, c, width); sum = 0.0; for (j = -n; j <= n; j++) sum += (double) (image[LinesUtil.LINCOOR(LinesUtil.BR(r + j, height), c, width)]) * mask[(j + n)]; h[l] = (float) sum; } } for (r = height - n; r < height; r++) { for (c = 0; c < width; c++) { l = LinesUtil.LINCOOR(r, c, width); sum = 0.0; for (j = -n; j <= n; j++) sum += (double) (image[LinesUtil.LINCOOR(LinesUtil.BR(r + j, height), c, width)]) * mask[(j + n)]; h[l] = (float) sum; } } } /** * Convolve cols gauss. * * @param h * the h * @param mask * the mask * @param n * the n * @param k * the k * @param width * the width * @param height * the height */ /* Convolve the columns of an image with the derivatives of a Gaussian. */ private void convolve_cols_gauss(float[] h, double[] mask, int n, float[] k, int width, int height) { int j, r, c, l; double sum; /* Inner region */ for (r = 0; r < height; r++) { for (c = n; c < width - n; c++) { l = LinesUtil.LINCOOR(r, c, width); sum = 0.0; for (j = -n; j <= n; j++) sum += h[(l + j)] * mask[(j + n)]; k[l] = (float) sum; } } /* Border regions */ for (r = 0; r < height; r++) { for (c = 0; c < n; c++) { l = LinesUtil.LINCOOR(r, c, width); sum = 0.0; for (j = -n; j <= n; j++) sum += h[LinesUtil.LINCOOR(r, LinesUtil.BC(c + j, width), width)] * mask[(j + n)]; k[l] = (float) sum; } } for (r = 0; r < height; r++) { for (c = width - n; c < width; c++) { l = LinesUtil.LINCOOR(r, c, width); sum = 0.0; for (j = -n; j <= n; j++) sum += h[LinesUtil.LINCOOR(r, LinesUtil.BC(c + j, width), width)] * mask[(j + n)]; k[l] = (float) sum; } } } /** * Convolve gauss. * * @param image * the image * @param k * the k * @param width * the width * @param height * the height * @param sigma * the sigma * @param deriv_type * the deriv type */ /* Convolve an image with a derivative of the Gaussian. */ public void convolve_gauss(float[] image, float[] k, int width, int height, double sigma, int deriv_type) { double[] hr = null, hc = null; double[] maskr, maskc; MutableLong nr = new MutableLong(), nc = new MutableLong(); float[] h; h = new float[(width * height)]; switch (deriv_type) { case LinesUtil.DERIV_R: hr = compute_gauss_mask_1(nr, sigma); hc = compute_gauss_mask_0(nc, sigma); break; case LinesUtil.DERIV_C: hr = compute_gauss_mask_0(nr, sigma); hc = compute_gauss_mask_1(nc, sigma); break; case LinesUtil.DERIV_RR: hr = compute_gauss_mask_2(nr, sigma); hc = compute_gauss_mask_0(nc, sigma); break; case LinesUtil.DERIV_RC: hr = compute_gauss_mask_1(nr, sigma); hc = compute_gauss_mask_1(nc, sigma); break; case LinesUtil.DERIV_CC: hr = compute_gauss_mask_0(nr, sigma); hc = compute_gauss_mask_2(nc, sigma); break; } maskr = hr;// + nr; Wird ersetzt in den eigentlichen Funktionen, indem ich z.B. in // convolve_rows_gauss immer beim Zugriff auf mask n dazuaddiere maskc = hc;// + nc; convolve_rows_gauss(image, maskr, nr.intValue(), h, width, height); convolve_cols_gauss(h, maskc, nc.intValue(), k, width, height); } }