Você está na página 1de 50

12/11/2008

Anisotropic Diffusion Model for Edge Detection: a Java Implementation


Jos Iguelmar Miranda

Jos Iguelmar Miranda

Anisotropic Diffusion Edge Detection: Implementation


Introduction

Model for a Java

The purpose of this document is to present the Java implementation of the anisotropic diffusion filter to attenuate noise and detect edges in digital images, based on the model presented by Perona & Malik (1990). Edge detection is one of the most fundamental processes when analyzing digital images, with a great availability of algorithms. Edges are responsible for the delineation of an objects format. They are the transition regions and, generally, define the edges between the object and the background as well as the contour among intersecting or overlapping objects. This means that the edges of an object, in a scene, can be detected. This way, one can localize objects and have their basic properties measured, like area, perimeter, and shape. The edge detection process is a qualified tool in the image analyses. Noise is a common problem in digital images, due to assorted causes, like camera and lens used, sensor tilting, targets temperature, atmospheric effects, etc. It is unlike that the area of two pixels with the same gray level, in ground, will have the same gray level in the digital image. Noises belong to two groups: random and systematic. The random types are only perceived through a statistic distribution while systematic ones are easy to detect and suppress. The net result of noises in images is to produce a random variation in the pixels gray levels values, such that the ideal edge is not found in the available images. Random noise is always present in the image, but not the systematic. The problem is that the noise cannot be identified and measured precisely, since one cannot differentiate its

Jos Iguelmar Miranda

contribution in the gray level values in the image pixels. Happily, sometimes, the random noise can be characterized by its effect in the image, expressed as a probability distribution with specific mean and standard deviation (Parker, 1997). Before working with an image, it is necessary to filter this kind of noise, normally, using an edge detection process. Generally, the edge detection operators can be classified in three groups: (a) those using partial derivatives, approximated by differences, in the discrete case of digital images, whose function is to identify places where there are great intensity changes; (b) those that model the edge with a small dimension kernel, showing abstract properties of an ideal edge; and (c) operators that use mathematical models to represent the edges, based on partial differential equations (PDE), or diffusion models, searching for the functions maxima or minima. The latter is the one presented here. Anisotropic diffusion or non linear processes, have been used lately to enhance the edge detection task and suppress image noise in several application fields, among others, medical images (Chung & Sapiro, 2000; Demirkaya, 2002); agriculture (Karantzalos & Argialas, 2004), and three dimensional conformal radiotherapy (3D CRT) and intensity modulated radiation therapy (IMRT) (Gibou et al., 2005).

The Anisotropic Diffusion Model


The importance of describing an image in multiple scales was recognized in the initial years of computer vision. The formalism of this problem is tied to the idea of image filtering or transformation of its scale-space. Scale-space theory is a theoretical base for representing images or signals in multiple scales, developed by the image processing and signal processing communities. It is a formal theory to manipulate images structures in differing scales, such that attributes in major scales can be successively suppressed and a scale parameter, t, can be linked to each level of the scale-space representation. The basic idea for this approach is to embed the original image, I0(x, y), in a family of derived images, I(x, y; t), obtained by convolving the original image with a Gaussian kernel, G(x, y; t), of variance (time) t (Perona & Malik, 1990):

Jos Iguelmar Miranda

(1) Where: I(x, y; t) = I0(x, y)* G(x, y; t) (2)

The time t is a scale parameter: increases in t yield simpler images representations or coarse resolutions. The original image embedding in this one parameter family or simplified images is called scale-space. This one parameter family resolution in t of derived imagery may be viewed as the solution of the heat conduction, or diffusion, equation (a second order differential partial equation):

2 f 2 f It = I = 2 + 2 x y

(3)

With the initial condition I(x, y; 0) = I0(x, y), the original image (Perona & Malik, 1990). There are variants showing that this is the canonical form to generate a linear scale-space, based on the fact that newer structures cannot be created from a minor to a major scale. Motivation for creating a representation of scale-space from data comes from the fact that objects in the real world are comprised of differing structures and scales. This implies that such objects, contrary to mathematically idealized entities, like points and lines, may appear in different ways, depending on the observation scale. For instance, the concept of a tree is suitable in a meter scale, whilst the concept of leaves and molecules is suitable in larger scales. In a computer vision system, analyzing an unknown scene, there is no way for someone to know, a priori, what scales are convenient to describe the data. This way, the only reasonable approach is to consider the description in all scales, simultaneously. From the scale-space representation, a great diversity of image processing and computer vision operations can be used, like feature detection, classification, segmentation, moving estimates, and shape calculation, based on combination of Gaussian derivatives in multiple scales. Koenderink (1986) motivated the diffusion equation formulation presenting two criteria: (1) causality: any feature at a coarse level of resolution possesses a cause (not necessarily unique) at a finer level of resolution; the reverse need not be true. This means that no spurious

Jos Iguelmar Miranda

detail should be generated when the resolution is decreased; (2) homogeneity and isotropy: the blurring is required to be space invariant. The causality criterion does not require a Gaussian kernel to do the blurring, though it is the most used and simplest. Perona & Malik (1990) criticized this standard scale-space model and presented an additional set of criteria to obtain descriptions in multiple scales semantically meaningful, condition obtained by allowing variation in the diffusion coefficient. In their new proposal, the causality criterion is still satisfied. In the standard scale-space model the true positioning of an edge at a coarse scale is not directly available in the coarse scale image. Edges positions in the low resolution or coarse scales are shifted from their original position. The reason for this spatial distortion is due to the fact that the Gaussian blurring does not respect the natural boundaries of the objects in the scene, making them fuzzier. Based on these assumptions, Perona & Malik (1990) announced the criteria that must be satisfied for generating multiscale semantically meaningful description of images: (1) causality: a scale-space representation should have the property that no spurious detail should be generated passing from finer to coarser scale; (2) immediate localization: at each resolution, the region boundaries should be sharp and coincide with the semantically meaningful at that resolution; and (3) piecewise smoothing: at all scales, intraregion smoothing should occur preferentially over interregion smoothing. The solution addressed by the authors to modify the linear scale-space model happened in the diffusion equation, where the diffusion coefficient, c, was assumed to be a constant independent of the space localization. They demonstrated that a suitable choice of c(x, y; t) would enable someone to satisfy the second and third criteria listed. Besides, this could be done without sacrificing the causality criterion. They proposed the following anisotropic diffusion equation: It = div(c(x, y; t)I) = c(x, y; t)I + c I (4)

Where div is the divergence operator; e represent the gradient and Laplacian operators, respectively, with respect to the space variable. Equation (4) becomes the isotropic heat diffusion equation It = cI if c(x, y; t) is a constant.

Jos Iguelmar Miranda

Suppose that at time (scale) t, the appropriate location of the regions edges were known for that scale. The goal was smoothing within a region instead of smoothing across the edges. This was done by adjusting the conduction coefficient to be one within each region and zero at their edges. The smoothing could happen separately in each region with no interactions between regions. The edges would remain sharp. The success of the diffusion process in satisfying the three listed criteria depended on how precise was the estimated hit of the edges location. A good estimate for edges position with outstanding results was the gradient of the brightness function. The authors showed that if the diffusion coefficient was chosen locally as a function of the magnitude of the gradient of the brightness function according to: c(x, y; t) = g(||I(x, y; t)||) (5)

Then the edges brightness would be preserved and outlined if the function g() was appropriately chosen. The choice of g(), according to the authors, was reduced to a subclass of functions monotonically decreasing.

Case study
Equation (4) can be discretized in a squared lattice, or 4-nearest-neighbors, with brightness values (pixels) associated with the nodes and the conduction coefficients associated with the arcs of the lattice. A discretization of the Laplacian can be used according to: (6) Where 0 in order to keep the numeric schema stable; N, S, E, and W are the mnemonic subscripts for North, South, East and West; the superscripts and subscripts on the square brackets are applied to all the terms it encloses, and the symbol indicates nearestneighbors differences:

Jos Iguelmar Miranda

(7)

The gradient value can be computed in differing neighborhood structures achieving different results between accuracy and locality. The simplest choice consists in approximating the norm of the gradient at each arc location with the absolute value of its projection along the direction of the arc, according to:

(8)

This is not the exact discretization of (4), but of a similar diffusion equation in which the conduction tensor is diagonal with input values g(|Ix|) and g(|Iy|) instead of g(||Ix||) and g(||Ix||). This discretization schema preserves the properties of the continuous equation (4), thus, keeping the total brightness quantity of the image. Equations (6), (7), and (8) were used to generate the following images (Fig. 1). The original image represented the initial conditions and adiabatic boundary conditions, i.e., setting the conduction coefficient equals to zero at the edges of the image. If a constant value is assigned to the conduction coefficient, c, then it yields a Gaussian smoothing. The use of different functions for g() yielded similar results. Images produced in this document used g() as: (9) The scale-space produced by this function emphasizes high contrast edges over low contrast edges. In the upper left corner of Fig. 1 is the original image. All other images were filtered with the anisotropic diffusion algorithm: upper right corner, filtered after five iterations; lower left corner, after ten iterations; and lower right corner, after twenty iterations. As the iterations increases, intraregions details are lost, while the borders are kept. For instance, details of

Jos Iguelmar Miranda

sugar cane plantation rows, differing spectral values inside the center pivot, fringing vegetation and bare soil are progressively vanishing, disappearing, eventually.

Jos Iguelmar Miranda

Figure 1 Anisotropic diffusion: original and filtered images (detail in text body)

The source code


Below, is the source code for the program AnisotropicDiffusionFilter.java. The program was developed as a standard Java code. It uses the additional Matriz.java program, also added. You can add them to an IDE, like NetBeans or Eclipse, or simply compile and execute through a DOS prompt. Initially, it was developed to run in a DOS prompt, as you can see

Jos Iguelmar Miranda

how it reads the needed parameters. Running the program with the threshold parameter equals to fifteen yields good response to edge preservation. Also, using Perona-Malik function one gives better results than function two, which trends to blur the edges. Using standard deviation value greater than zero also blurs the image edges. The iterations parameter works within regions, leaving them smoother. As this value increases, more intraregions details are lost.
/*********************************************************************************** AnisotropicDiffusionFilter.java - noise attenuation using anisotropic diffusion.

WRITTEN BY: Jos Iguelmar Miranda & Joo Camargo Neto.

DATE: November 2006

DOCUMENTATION: See http://www.cnptia.embrapa.br/files/ct72.pdf

Copyright (c) 2006 Embrapa Informtica Agropecuria

PERMISSION TO COPY: This program is free software, under the GNU General Public License (GPL); permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement to the authors, Jos Iguelmar Miranda & Joo Camargo Neto, at www.cnptia.embrapa.br, appears in all copies.

Embrapa Informtica Agropecuria makes no representations about the suitability or fitness of the software for any or for a particular purpose. Embrapa Informtica Agropecuria shall not be liable for any damages suffered as a result of using, modifying or distributing this software or its derivatives.

For a copy of GNU General Public License, write to: Free Software Foundation, Inc., 59 Temple Street, Suite 330, Boston, MA 02111-1307 USA.

**********************************************************************************

Description:

Jos Iguelmar Miranda

This program implements the edge detection filter using the anisotropic diffusion model. Reference paper: PERONA, P.; MALIK, J. "Scale-space and edge detection using anisotropic diffusion", IEEE Transactions on Pattern Analysis and Machine Intelligence, 12(7), pp. 629-639, 1990.

This program uses Matriz.java.

Input: 1. 'iterations': how many times to filter the source image. It means time, in equations (1) and (2) in the body of the document. For instance, iterations = 10.

2. 'Perona-Malik function': '1': g(grad(I)) = exp{-(|grad(I)|/K)^2} [equation (9) in this document] '2': g(grad(I)) = 1/{1+(|grad(I)|/K)^2} [equation not available in this doc]

The scale-space yielded by these functions is different: - The former equation emphasizes edges with high contrast over low contrast edges. - The latter equation emphasizes wide regions over small ones.

3. 'threshold': a value related to 'K', below which 'g(.)' is monotonically increasing and above, 'g(.)' is monotonically decreasing; as a result, smoothes small discontinuities and enhance edges. For instance, threshold = 15.

4. 'sigma2': if exists, computes the gradient of the diffusion coefficient, convolved with the Gaussian kernel using variance = sigma2. For instance, if not using sigma, then sigma2 = 0.0.

Output:

JFrame with source and filtered images.

Informaes do CVS: $Source$: $Revision$: $Date$:

10

Jos Iguelmar Miranda

***********************************************************************************/

// generic packages import java.io.File; import java.io.IOException;

// AWT packages import java.awt.image.WritableRaster; import java.awt.image.BufferedImage; import java.awt.image.Raster; import java.awt.GridLayout;

// Swing packages for GUI import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.ImageIcon; import javax.swing.JScrollPane;

// immediate reading mode for J2SE 1.4+ import javax.imageio.ImageIO;

public class AnisotropicDiffusionFilter extends JFrame {

public static void main(String args[]) { int iterations = 0, threshold = 0, typePM = 1; double sigma2 = 0.0;

// All parms ok? if (args.length != 5) { String msga = "Usage: java -cp . AnisotropicDiffusionFilter "; String msgb = "<image> <iterations>"; String msgc = " <type Perona-Malik function: 1 | 2> <threshold> "; String msgd = "<sigma2>";

11

Jos Iguelmar Miranda

System.out.println(msga + msgb + msgc + msgd); System.exit(0); }

// Show JFrame decorated with Swing JFrame.setDefaultLookAndFeelDecorated(true);

long eq_time = System.currentTimeMillis();

try { iterations = Integer.parseInt(args[1]); } catch (NumberFormatException e) { String st = "Parameter 'iterations' invalid"; System.out.println(st); System.exit(0); }

try { typePM = Integer.parseInt(args[2]); } catch (NumberFormatException e) { String st = "Parameter 'type Perona-Malik function' invalid"; System.out.println(st); System.exit(0); }

try { threshold = Integer.parseInt(args[3]); } catch (NumberFormatException e) { String st = "Parameter 'threshold' invalid"; System.out.println(st); System.exit(0); }

if (typePM < 1 || typePM > 2) {

12

Jos Iguelmar Miranda

System.out.println("Defining type Perona-Malik function = 1"); typePM = 1; }

try { sigma2 = Double.parseDouble(args[4]); } catch (NumberFormatException e) { String st = "Parameter 'sigma2' invalid"; System.out.println(st); System.exit(0); }

if (sigma2 < 0.0) { System.out.println("Using sigma2 = 0.0"); sigma2 = 0.0; }

System.out.println("\nAnisotropic diffusion filter - Parameters:\n"); String st = "\t#iterations: "; System.out.println(st + iterations); st = "\n\ttype Perona-Malik function: "; System.out.println(st + typePM); st = "\n\tthreshold: "; System.out.println(st + threshold); st = "\n\tvariance: "; System.out.println(st + sigma2 + "\n");

AnisotropicDiffusionFilter c = new AnisotropicDiffusionFilter(args[0], iterations, typePM, threshold, sigma2);

eq_time = System.currentTimeMillis() - eq_time; String msg = "AnisotropicDiffusionFilter: run time "; System.out.println(msg + eq_time + " milisseg.");

13

Jos Iguelmar Miranda

// Close application clicking on "close" c.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); c.setVisible(true); }

public AnisotropicDiffusionFilter(String aFile, int iterations, int typePM, int threshold, double sigma2) {

// Define BufferedImage BufferedImage src = null, dest = null; int w, h, tipo, nBandas, pixels[][], bordas[][], bordasTriplo[][][]; JLabel img1, img2;

// Does image exist? File file = new File(aFile); try { src = ImageIO.read(file); } catch(Exception e) { System.out.println("Imagem '" + aFile + "' nao existe."); System.exit(0); }

// Identify frame setTitle("Anisotropic diffusion: " + file.getName());

w = src.getWidth(); h = src.getHeight(); nBandas = src.getSampleModel().getNumBands(); System.out.println("Number of image bands: " + nBandas + "\n");

// If imagem is gray level ... if (nBandas == 1) { pixels = lePixels(src, 0); if (typePM == 1) bordas = AnisotropicDiffusion(pixels, iterations, "pm1", threshold, sigma2);

14

Jos Iguelmar Miranda

else bordas = AnisotropicDiffusion(pixels, iterations, "pm2", threshold, sigma2); dest = criaImagem(bordas); // ...else, color image } else { bordasTriplo = new int[3][w][h]; pixels = lePixels(src, 0); if (typePM == 1) bordasTriplo[0] = AnisotropicDiffusion(pixels, iterations, "pm1", threshold, sigma2); else bordasTriplo[0] = AnisotropicDiffusion(pixels, iterations, "pm2", threshold, sigma2); pixels = lePixels(src, 1); if (typePM == 1) bordasTriplo[1] = AnisotropicDiffusion(pixels, iterations, "pm1", threshold, sigma2); else bordasTriplo[1] = AnisotropicDiffusion(pixels, iterations, "pm2", threshold, sigma2); pixels = lePixels(src, 2); if (typePM == 1) bordasTriplo[2] = AnisotropicDiffusion(pixels, iterations, "pm1", threshold, sigma2); else bordasTriplo[2] = AnisotropicDiffusion(pixels, iterations, "pm2", threshold, sigma2); dest = criaImagem(bordasTriplo); }

// Record image String search = "."; int i = file.getName().indexOf(search); String prefixo = file.getName().substring(0, i); try { String nome = "C:\\temp\\" + prefixo + "_FDA" + iterations + ".png"; ImageIO.write(dest, "png", new File(nome)); System.out.println("\nStoring image -> " + nome + "\n"); } catch (IOException e) { System.out.println("Problem storing file");

15

Jos Iguelmar Miranda

System.exit(0); } // Define gridLayout 1 x 2 getContentPane().setLayout(new GridLayout(1, 2)); img1 = new JLabel(new ImageIcon(src)); img2 = new JLabel(new ImageIcon(dest)); setSize(2*w, h); getContentPane().add(new JScrollPane(img1)); getContentPane().add(new JScrollPane(img2)); }

private int[][] lePixels(BufferedImage src, int banda) { int w, h, pixels[][] = null;

w = src.getWidth(); h = src.getHeight(); pixels = new int[w][h]; Raster srcR = src.getRaster();

for (int i = 0; i < h; i++) for (int j = 0; j < w; j++) { pixels[j][i] = srcR.getSample(j, i, banda); }

return pixels; }

private int[][] AnisotropicDiffusion(int[][] in, int iter, String metodo, int threshold, double sigma2){ int h, w, bfi[][], inRet[][]; double dt, imagemD[][]; Matriz matrizPM = new Matriz(in);

// Gradient copies

16

Jos Iguelmar Miranda

Matriz cN, cS, cL, cO, mGradienteN, mGradienteS, mGradienteL, mGradienteO, j0 = null; w = in.length; h = in[0].length; bfi = new int[w][h]; dt = 0.2;

System.out.println("Running..."); for (int i = 0; i < iter; i++){ System.out.print(".");

if (sigma2 > 0.0) { j0 = matrizPM.copy(); imagemD = matrizPM.getArrayReference(); for (int lin = 0; lin < h; lin++) for (int col = 0; col < w; col++) bfi[col][lin] = (int) imagemD[col][lin]; inRet = gauss(bfi, 5, sigma2); matrizPM = new Matriz(inRet); }

mGradienteN = matrizPM.copy(); mGradienteS = matrizPM.copy(); mGradienteL = matrizPM.copy(); mGradienteO = matrizPM.copy();

// Gradient in directions N, S, L (E) and O (W) mGradienteN.gradiente(4); mGradienteS.gradiente(3); mGradienteL.gradiente(2); mGradienteO.gradiente(1);

// Save copy of images with gradient for further calculations cN = mGradienteN.copy();

17

Jos Iguelmar Miranda

cS = mGradienteS.copy(); cL = mGradienteL.copy(); cO = mGradienteO.copy();

if (metodo.equals("pm1")){ cN.abs(); cN.divide((double) threshold); cN.elevaQuadrado(); cN.timesEquals(-1.0); cN.exp();

cS.abs(); cS.divide((double) threshold); cS.elevaQuadrado(); cS.timesEquals(-1.0); cS.exp();

cL.abs(); cL.divide((double) threshold); cL.elevaQuadrado(); cL.timesEquals(-1.0); cL.exp();

cO.abs(); cO.divide((double) threshold); cO.elevaQuadrado(); cO.timesEquals(-1.0); cO.exp(); } else if (metodo.equals("pm2")){ cN.abs(); cN.divide((double) threshold); cN.elevaQuadrado(); cN.adiciona(1.0);

18

Jos Iguelmar Miranda

cN.inverteElemento();

cS.abs(); cS.divide((double) threshold); cS.elevaQuadrado(); cS.adiciona(1.0); cS.inverteElemento();

cL.abs(); cL.divide((double) threshold); cL.elevaQuadrado(); cL.adiciona(1.0); cL.inverteElemento();

cO.abs(); cO.divide((double) threshold); cO.elevaQuadrado(); cO.adiciona(1.0); cO.inverteElemento(); } if (sigma2 > 0.0){ mGradienteN = j0.copy(); mGradienteS = j0.copy(); mGradienteL = j0.copy(); mGradienteO = j0.copy();

// Compute filtered image gradient in direction N, S, L (E) and O (W) mGradienteN.gradiente(4); mGradienteS.gradiente(3); mGradienteL.gradiente(2); mGradienteO.gradiente(1); matrizPM = j0.copy();

19

Jos Iguelmar Miranda

cN.multiplica(mGradienteN); cS.multiplica(mGradienteS); cL.multiplica(mGradienteL); cO.multiplica(mGradienteO);

cN.plusEquals(cS); cO.plusEquals(cL); cN.plusEquals(cO);

cN.timesEquals(dt);

matrizPM.plusEquals(cN); }

imagemD = matrizPM.getArrayReference(); for (int i = 0; i < h; i++) for (int j = 0; j < w; j++) bfi[j][i] = (int) imagemD[j][i];

System.out.println("\n"); return bfi; }

private BufferedImage criaImagem(int[][] in) { int w, h, tipo, pixels[], ind = 0; BufferedImage dest = null;

w = in.length; h = in[0].length; pixels = new int[w*h]; tipo = BufferedImage.TYPE_BYTE_GRAY; dest = new BufferedImage(w, h, tipo); WritableRaster destWR = dest.getRaster();

20

Jos Iguelmar Miranda

for(int lin = 0; lin < h; lin++) for(int col = 0; col < w; col++) pixels[ind++] = in[col][lin];

destWR.setPixels(0, 0, w, h, pixels); return dest; }

private BufferedImage criaImagem(int[][][] in) { int w, h, tipo; BufferedImage dest = null;

w = in[0].length; h = in[0][0].length; tipo = BufferedImage.TYPE_3BYTE_BGR; dest = new BufferedImage(w, h, tipo); WritableRaster destWR = dest.getRaster();

for(int lin = 0; lin < h; lin++) for(int col = 0; col < w; col++) for(int b = 0; b < 3; b++) destWR.setSample(col, lin, b, in[b][col][lin]); return dest; }

private int[][] gauss(int[][] in, int ks, double sigma2) { int w, h, hks, // half kernel size eI[][] = null, tmpVec[]; double flt[][] = null, x = 0.0, y = 0.0, soma = 0.0, xL = 0.0, xR = 0.0, xU = 0.0, xD = 0.0;

w = in.length; h = in[0].length; hks = (int) (ks - 1)/2;

21

Jos Iguelmar Miranda

flt = new double[2*hks+1][2*hks+1]; if (h < ks) { System.out.println ("1D convolution happened"); } else { // 2D convolution for (int y1 = -hks; y1 <= hks; y1++){ for (int x1 = -hks; x1 <= hks; x1++) { x = (double) x1*x1; y = (double) y1*y1; // 2D Gaussian flt[y1+hks][x1+hks] = Math.exp(-1*(x + y)/(2*sigma2)); soma += flt[y1+hks][x1+hks]; } } // Normalize values in flt for (int y1 = 0; y1 <= 2*hks; y1++) for (int x1 = 0; x1 <= 2*hks; x1++) flt[y1][x1] /= soma; tmpVec = new int[hks]; if (hks > 1) { eI = new int[w+2*hks][h+2*hks]; // Horizontal expansion for (int lin = 0; lin < h; lin++) { for (int col = 0; col < w; col++) { // First column of image if (col == 0){ xL = mean(retornaPixels(in, lin, col, hks, "horizontal")); for(int k = 0; k < hks; k++) eI[k][lin] = (int) xL; } // Last column if image if (col == w - 1){ xR = mean(retornaPixels(in, lin, w - hks, hks, "horizontal")); for (int k = 0; k < hks; k++)

22

Jos Iguelmar Miranda

eI[w+hks+k][lin] = (int) xR; } // Copy image to the center of vector eI eI[col+hks][lin+hks] = in[col][lin]; } } // Vertical expansion int weI = eI.length; int heI = eI[0].length; for (int col = 0; col < weI; col++){ xU = mean(retornaPixels(eI, hks, col, hks, "vertical")); for (int k = 0; k < hks; k++) eI[col][k] = (int) xU; xD = mean(retornaPixels(eI, heI-2*hks, col, hks, "vertical")); for (int k = 0; k < hks; k++) eI[col][heI-hks+k] = (int) xD; } } else {} }

return convolve(eI, flt); }

private int[][] convolve(int[][] in, double [][]filtro){ int wI = in.length; int hI = in[0].length; int wF = filtro.length; int hF = filtro[0].length; int hks = (wF -1)/2; double soma; int[][] vecRet = new int[wI-2*hks][hI - 2*hks];

for(int lin = 0; lin < hI - 2*hks; lin++){ for(int col = 0; col < wI - 2*hks; col++){

23

Jos Iguelmar Miranda

soma = 0.0; for(int linF = 0; linF < hF; linF++){ for(int colF = 0; colF < wF; colF++){ soma += in[col+colF][lin+linF]*filtro[linF][colF]; } } soma /= hF*wF; vecRet[col][lin] = (int) soma; } } return vecRet; }

//=============== Mean ===================== private double mean(int[] p) { double sum = 0; // sum of all the elements for (int i = 0; i < p.length; i++) { sum += p[i]; } return sum / p.length; }

// Return pixels values within an image private int[] retornaPixels(int[][] in, int lin, int col, int tam, String dir) { int i, vec[] = null;

if (dir.equals("horizontal")){ if(col + tam <= in.length) { vec = new int[tam]; for(i = 0; i < tam; i++) vec[i] = in[col+i][lin]; } } else { // vertical if (lin + tam <= in[0].length) {

24

Jos Iguelmar Miranda

vec = new int[tam]; for (i = 0; i < tam; i++) vec[i] = in[col][lin+i]; } } return vec; } } // end of AnisotropicDiffusionFilter

/*********************************************************************************** WRITTEN BY: Dr Michael Thomas Flanagan DATE: June 2002

UPDATE: 21 April 2004, 19 January 2005, 1 May 2005 DOCUMENTATION: See Michael Thomas Flanagan's Java library on-line web page: Matrix.html Copyright (c) April 2004 Michael Thomas Flanagan PERMISSION TO COPY: Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software or its derivatives.

Informaes do CVS: $Source$: $Revision$:

25

Jos Iguelmar Miranda

$Date$: ***********************************************************************************/ import java.text.DecimalFormat; import java.util.Arrays; public class Matriz { // DATA VARIABLES private int nrow = 0; private int ncol = 0; private double matriz[][] = null; private int index[] = null; private double dswap = 1.0D; private boolean matrizCheck = true; // number of rows // number of columns // 2-D Matriz // row permutation index // row swap index // check on matrix status // true - no problems encountered // false - attempted a LU decomposition on a singular matrix private static final double TINY = 1.0e-30; // CONSTRUCTORS // Construct a nrow x ncol matrix of complex variables all equal to zero public Matriz(int nrow, int ncol){ this.nrow = nrow; this.ncol = ncol; this.matriz = new double[nrow][ncol]; this.index = new int[nrow]; for (int i = 0; i < nrow; i++) this.index[i] = i; } // Construct a nrow x ncol matrix of complex variables all equal to // the complex number const public Matriz(int nrow, int ncol, double constant){ this.nrow = nrow; this.ncol = ncol;

26

Jos Iguelmar Miranda

this.matriz = new double[nrow][ncol]; for (int i = 0; i < nrow; i++){ for (int j = 0; j < nrow; j++) this.matriz[i][j] = constant; } this.index = new int[nrow]; for (int i = 0; i < nrow; i++) this.index[i] = i; } // Construct matrix with a reference to an existing nrow x ncol 2-D // array of complex variables public Matriz(double[][] twoD){ this.nrow = twoD.length; this.ncol = twoD[0].length; for (int i = 0; i < nrow; i++){ if (twoD[i].length != ncol) throw new IllegalArgumentException("All rows must have the same length"); } this.matriz = twoD; this.index = new int[nrow]; for (int i = 0; i < nrow; i++) this.index[i] = i; } // Construct matrix with a reference to the 2D matrix and // permutation index of an existing ComplexMatriz bb. public Matriz(Matriz bb){ this.nrow = bb.nrow; this.ncol = bb.ncol; this.matriz = bb.matriz; this.index = bb.index; this.dswap = bb.dswap; }

// METHODS

27

Jos Iguelmar Miranda

// SET VALUES // Set the matrix with a copy of an existing nrow x ncol 2-D matrix of // complex variables public void setTwoDarray(double[][] aarray){ String msgA = "row length of this ComplexMatriz differs from that "; String msgA1 = "of the 2D array argument"; String msgB = "column length of this ComplexMatriz differs from that "; String msgB1 = "of the 2D array argument"; String msgC = "All rows must have the same length"; if (this.nrow != aarray.length) throw new IllegalArgumentException(msgA + msgA1); if (this.ncol != aarray[0].length) throw new IllegalArgumentException(msgB + msgB1); for (int i = 0; i < nrow; i++){ if (aarray[i].length != ncol) throw new IllegalArgumentException(msgC); for (int j = 0; j < ncol; j++){ this.matriz[i][j] = aarray[i][j]; } } } // Set an individual array element // i = row index / / j = column index // aa = value of the element public void setElement(int i, int j, double aa){ this.matriz[i][j] = aa; } // Set a sub-matrix starting with column index i, row index j // and ending with column index k, row index l public void setSubMatriz(int i, int j, int k, int l, double[][] smat){ if (i > k) throw new IllegalArgumentException("row indices inverted"); if (j > l) throw new IllegalArgumentException("column indices inverted");

28

Jos Iguelmar Miranda

int n = k-i+1, m = j-l+1; for (int p = 0; p < n; p++){ for (int q = 0; q < m; p++){ this.matriz[i+p][j+q] = smat[i][j]; } } } // Set a sub-matrix // row = array of row indices // col = array of column indices public void setSubMatriz(int[] row, int[] col, double[][] smat){ int n = row.length; int m = col.length; for (int p = 0; p < n; p++){ for (int q = 0; q < m; p++){ this.matriz[row[p]][col[q]] = smat[p][q]; } } } // Get the value of matrixCheck public boolean getMatrizCheck(){ return this.matrizCheck; } // SPECIAL MATRICES // Construct an identity matrix public static Matriz identityMatriz(int nrow){ Matriz u = new Matriz(nrow, nrow); for (int i = 0; i < nrow; i++){ u.matriz[i][i] = 1.0; } return u; } // Construct a complex scalar matrix

29

Jos Iguelmar Miranda

public static Matriz scalarMatriz(int nrow, double diagconst){ Matriz u = new Matriz(nrow, nrow); double[][] uarray = u.getArrayReference(); for (int i = 0; i < nrow; i++){ for (int j = i; j < nrow; j++){ if (i == j){ uarray[i][j] = diagconst; } } } return u; } // Construct a diagonal matrix public static Matriz diagonalMatriz(int nrow, double[] diag){ String msgA = "matriz dimension differs from diagonal array length"; if (diag.length != nrow) throw new IllegalArgumentException(msgA); Matriz u = new Matriz(nrow, nrow); double[][] uarray = u.getArrayReference(); for (int i = 0; i < nrow; i++){ uarray[i][i] = diag[i]; } return u; } // GET VALUES // Return the number of rows public int getNrow(){ return this.nrow; } // Return the number of columns public int getNcol(){ return this.ncol; }

30

Jos Iguelmar Miranda

// Return a reference to the internal 2-D array public double[][] getArrayReference(){ return this.matriz; } // Return a reference to the internal 2-D array // included for backward compatibility with incorrect earlier documentation public double[][] getArrayPointer(){ return this.matriz; } // Return a copy of the internal 2-D array public double[][] getArrayCopy(){ double[][] c = new double[this.nrow][this.ncol]; for (int i = 0; i < nrow; i++){ for (int j = 0; j < ncol; j++){ c[i][j] = this.matriz[i][j]; } } return c; } // Return a single element of the internal 2-D array public double getElement(int i, int j){ return this.matriz[i][j]; } // Return a single element of the internal 2-D array // included for backward compatibility with incorrect earlier documentation public double getElementCopy(int i, int j){ return this.matriz[i][j]; } // Return a single element of the internal 2-D array // included for backward compatibility with incorrect earlier documentation public double getElementPointer(int i, int j){ return this.matriz[i][j];

31

Jos Iguelmar Miranda

} // Return a sub-matrix starting with column index i, row index j // and ending with column index k, row index l public Matriz getSubMatriz(int i, int j, int k, int l){ if (i > k) throw new IllegalArgumentException("row indices inverted"); if (j > l) throw new IllegalArgumentException("column indices inverted"); int n = k-i+1, m = j-l+1; Matriz smat = new Matriz(n, m); double[][] sarray = this.getArrayReference(); for (int p = 0; p < n; p++){ for (int q = 0; q < m; p++){ sarray[p][q] = this.matriz[i+p][j+q]; } } return smat; } // Return a sub-matrix // row = array of row indices // col = array of column indices public Matriz getSubMatriz(int[] row, int[] col){ int n = row.length; int m = col.length; Matriz smat = new Matriz(n, m); double[][] sarray = this.getArrayReference(); for (int i = 0; i < n; i++){ for (int j = 0; j < m; j++){ sarray[i][j] = this.matriz[row[i]][col[j]]; } } return smat; } // Return a reference to the permutation index array

32

Jos Iguelmar Miranda

public int[] getIndexReference(){ return this.index; } // Return a reference to the permutation index array // included for backward compatibility with incorrect earlier documentation public int[] getIndexPointer(){ return this.index; } // Return a copy of the permutation index array public int[] getIndexCopy(){ int[] indcopy = new int[this.nrow]; for (int i = 0; i < this.nrow; i++){ indcopy[i] = this.index[i]; } return indcopy; } // Return the row swap index public double getSwap(){ return this.dswap; } // COPY // Copy a Matriz [static method] public static Matriz copy(Matriz a){ if (a == null){ return null; } else { int nr = a.getNrow(); int nc = a.getNcol(); double[][] aarray = a.getArrayReference(); Matriz b = new Matriz(nr,nc); b.nrow = nr; b.ncol = nc; double[][] barray = b.getArrayReference();

33

Jos Iguelmar Miranda

for (int i = 0; i < nr; i++){ for (int j = 0; j < nc; j++){ barray[i][j] = aarray[i][j]; } } for (int i = 0; i < nr; i++) b.index[i] = a.index[i]; return b; } } // Copy a Matriz [instance method] public Matriz copy(){ if (this == null){ return null; } else { int nr = this.nrow; int nc = this.ncol; Matriz b = new Matriz(nr,nc); double[][] barray = b.getArrayReference(); b.nrow = nr; b.ncol = nc; for (int i = 0; i < nr; i++){ for (int j = 0; j < nc; j++){ barray[i][j] = this.matriz[i][j]; } } for (int i = 0; i < nr; i++) b.index[i] = this.index[i]; return b; } } // Clone a Matriz public Object clone(){

34

Jos Iguelmar Miranda

if (this == null){ return null; } else { int nr = this.nrow; int nc = this.ncol; Matriz b = new Matriz(nr,nc); double[][] barray = b.getArrayReference(); b.nrow = nr; b.ncol = nc; for (int i = 0; i < nr; i++){ for (int j = 0; j < nc; j++){ barray[i][j] = this.matriz[i][j]; } } for (int i = 0; i < nr; i++) b.index[i] = this.index[i]; return (Object) b; } } // ADDITION // Add this matrix to matrix B. This matrix remains unaltered [instance method] public Matriz plus(Matriz bmat){ if ((this.nrow != bmat.nrow)||(this.ncol != bmat.ncol)){ throw new IllegalArgumentException("Array dimensions do not agree"); } int nr = bmat.nrow; int nc = bmat.ncol; Matriz cmat = new Matriz(nr,nc); double[][] carray = cmat.getArrayReference(); for (int i = 0; i < nr; i++){ for (int j = 0; j < nc; j++){ carray[i][j] = this.matriz[i][j] + bmat.matriz[i][j]; } } return cmat; }

35

Jos Iguelmar Miranda

// Add matrices A and B [static method] public static Matriz plus(Matriz amat, Matriz bmat){ if ((amat.nrow != bmat.nrow)||(amat.ncol != bmat.ncol)){ throw new IllegalArgumentException("Array dimensions do not agree"); } int nr = amat.nrow; int nc = amat.ncol; Matriz cmat = new Matriz(nr,nc); double[][] carray = cmat.getArrayReference(); for (int i = 0; i < nr; i++){ for (int j = 0; j < nc; j++){ carray[i][j] = amat.matriz[i][j] + bmat.matriz[i][j]; } } return cmat; } // Add matrix B to this matrix [equivalence of +=] public void plusEquals(Matriz bmat){ if ((this.nrow != bmat.nrow)||(this.ncol != bmat.ncol)){ throw new IllegalArgumentException("Array dimensions do not agree"); } int nr = bmat.nrow; int nc = bmat.ncol; for (int i = 0; i < nr; i++){ for (int j = 0; j < nc; j++){ this.matriz[i][j] += bmat.matriz[i][j]; } } } // SUBTRACTION // Subtract matrix B from this matrix. // This matrix remains unaltered [instance method] public Matriz minus(Matriz bmat){ if ((this.nrow != bmat.nrow)||(this.ncol != bmat.ncol)){

36

Jos Iguelmar Miranda

throw new IllegalArgumentException("Array dimensions do not agree"); } int nr = this.nrow; int nc = this.ncol; Matriz cmat = new Matriz(nr,nc); double[][] carray = cmat.getArrayReference(); for (int i = 0; i < nr; i++){ for (int j = 0; j < nc; j++){ carray[i][j] = this.matriz[i][j] - bmat.matriz[i][j]; } } return cmat; } // Subtract matrix B from matrix A [static method] public static Matriz minus(Matriz amat, Matriz bmat){ if ((amat.nrow != bmat.nrow)||(amat.ncol != bmat.ncol)){ throw new IllegalArgumentException("Array dimensions do not agree"); } int nr = amat.nrow; int nc = amat.ncol; Matriz cmat = new Matriz(nr,nc); double[][] carray = cmat.getArrayReference(); for (int i = 0; i < nr; i++){ for (int j = 0; j < nc; j++){ carray[i][j] = amat.matriz[i][j] - bmat.matriz[i][j]; } } return cmat; } // Subtract matrix B from this matrix [equivlance of -=] public void minusEquals(Matriz bmat){ if ((this.nrow != bmat.nrow)||(this.ncol != bmat.ncol)){ throw new IllegalArgumentException("Array dimensions do not agree"); } int nr = bmat.nrow;

37

Jos Iguelmar Miranda

int nc = bmat.ncol; for (int i = 0; i < nr; i++){ for (int j = 0; j < nc; j++){ this.matriz[i][j] -= bmat.matriz[i][j]; } } } // MULTIPLICATION // Multiply this matrix by a matrix. [instance method] // This matrix remains unaltered. public Matriz times(Matriz bmat){ if (this.ncol != bmat.nrow) throw new IllegalArgumentException("Nonconformable matrices"); Matriz cmat = new Matriz(this.nrow, bmat.ncol); double[][] carray = cmat.getArrayReference(); double sum = 0.0D; for (int i = 0; i < this.nrow; i++){ for (int j = 0; j < bmat.ncol; j++){ sum = 0.0D; for (int k = 0; k < this.ncol; k++){ sum += this.matriz[i][k]*bmat.matriz[k][j]; } carray[i][j] = sum; } } return cmat; } // Multiply this matrix by a constant [instance method] // This matrix remains unaltered public Matriz times(double constant){ Matriz cmat = new Matriz(this.nrow, this.ncol); double [][] carray = cmat.getArrayReference(); for (int i = 0; i < this.nrow; i++){

38

Jos Iguelmar Miranda

for (int j = 0; j < this.ncol; j++){ carray[i][j] = this.matriz[i][j]*constant; } } return cmat; } // Multiply two complex matrices {static method] public static Matriz times(Matriz amat, Matriz bmat){ if (amat.ncol != bmat.nrow) throw new IllegalArgumentException("Nonconformable matrices"); Matriz cmat = new Matriz(amat.nrow, bmat.ncol); double [][] carray = cmat.getArrayReference(); double sum = 0.0D; for (int i = 0; i < amat.nrow; i++){ for (int j = 0; j < bmat.ncol; j++){ sum = 0.0D; for (int k = 0; k < amat.ncol; k++){ sum += (amat.matriz[i][k]*bmat.matriz[k][j]); } carray[i][j] = sum; } } return cmat; } // Multiply a matrix by a constant [static method] public static Matriz times(Matriz amat, double constant){ Matriz cmat = new Matriz(amat.nrow, amat.ncol); double [][] carray = cmat.getArrayReference(); for (int i = 0; i < amat.nrow; i++){ for (int j = 0; j < amat.ncol; j++){ carray[i][j] = amat.matriz[i][j]*constant; }

39

Jos Iguelmar Miranda

} return cmat; } // Multiply this matrix by a matrix [equivalence of *=] public void timesEquals(Matriz bmat){ if (this.ncol != bmat.nrow) throw new IllegalArgumentException("Nonconformable matrices"); double sum = 0.0D; for (int i = 0; i < this.nrow; i++){ for (int j = 0; j < bmat.ncol; j++){ sum = 0.0D; for (int k = 0; k < this.ncol; k++){ sum += (this.matriz[i][k]*bmat.matriz[k][j]); } this.matriz[i][j] = sum; } } } // Multiply this matrix by a constant [equivalence of *=] public void timesEquals(double constant){ for (int i = 0; i < this.nrow; i++){ for (int j = 0; j < this.ncol; j++){ this.matriz[i][j] *= constant; } } } // TRANSPOSE // Transpose of a complex matrix [instance method] public Matriz transpose(){ Matriz tmat = new Matriz(this.ncol, this.nrow); double[][] tarray = tmat.getArrayReference(); for (int i = 0; i < this.ncol; i++){

40

Jos Iguelmar Miranda

for (int j = 0; j < this.nrow; j++){ tarray[i][j] = this.matriz[j][i]; } } return tmat; } // Transpose of a matrix [static method] public static Matriz transpose(Matriz amat){ Matriz tmat = new Matriz(amat.ncol, amat.nrow); double[][] tarray = tmat.getArrayReference(); for (int i = 0; i < amat.ncol; i++){ for (int j = 0; j < amat.nrow; j++){ tarray[i][j] = amat.matriz[j][i]; } } return tmat; } // OPPOSITE // Opposite of a matrix [instance method] public Matriz opposite(){ Matriz opp = Matriz.copy(this); for (int i = 0; i < this.nrow; i++){ for (int j = 0; j < this.ncol; j++){ opp.matriz[i][j] =- this.matriz[i][j]; } } return opp; } // Opposite of a matrix [static method] public static Matriz opposite(Matriz amat){ Matriz opp = Matriz.copy(amat); for (int i = 0; i < amat.nrow; i++){ for (int j = 0; j < amat.ncol; j++){ opp.matriz[i][j] =- amat.matriz[i][j];

41

Jos Iguelmar Miranda

} } return opp; } // TRACE // Trace of a matrix [instance method] public double trace(){ double trac = 0.0D; for (int i = 0; i < Math.min(this.ncol,this.ncol); i++){ trac += this.matriz[i][i]; } return trac; } // Trace of a matrix [static method] public static double trace(Matriz amat){ double trac = 0.0D; for (int i = 0; i < Math.min(amat.ncol,amat.ncol); i++){ trac += amat.matriz[i][i]; } return trac; } /* ****************************************************************** */ // MTODOS NECESSRIOS PARA O ALGORITMO Perona-Malik // Implementao: Joo Camargo Neto & Jos Iguelmar Miranda. // METHODS USED BY Perona-Malik ALGORITHM // Construct matrix with a reference to an existing nrow x ncol 2-D // array of int variables (Joo 7/8/2006). public Matriz(int[][] twoI){ // nmero de colunas da matriz = num linhas twoI (w) this.nrow = twoI.length; // (h)

42

Jos Iguelmar Miranda

this.ncol = twoI[0].length; this.matriz = new double[nrow][ncol]; for (int i = 0; i < ncol; i++){ for (int j = 0; j < nrow; j++){ this.matriz[j][i] = (double) twoI[j][i]; } } this.index = new int[nrow]; for (int i = 0; i < nrow; i++) this.index[i] = i; } // Divide cada elemento da matriz por uma constante. // Divide each matrix element by a constant public void divide(double constant){ for (int i = 0; i < this.nrow; i++){ for (int j = 0; j < this.ncol; j++){ if (constant != 0.0) this.matriz[i][j] /= constant; else { String st = "Matriz::divide(double constant) -> divide by zero."; System.out.println(st); } } } } // Multiplica cada um dos elementos de duas matrizes (imagens). // Altera os valores de 'this.' // Multiply each one of matrixes elements public void multiplica(Matriz bMat){ for (int i = 0; i < this.nrow; i++){ for (int j = 0; j < this.ncol; j++){ this.matriz[i][j] *= bMat.matriz[i][j]; }

43

Jos Iguelmar Miranda

} } // Eleva ao quadrado cada elemento da matriz. // Square each one of matrixes elements public void elevaQuadrado(){ for (int i = 0; i < this.nrow; i++){ for (int j = 0; j < this.ncol; j++){ this.matriz[i][j] *= this.matriz[i][j]; } } } // Retorna o valor absoluto de cada elemento da matriz. // Return the absolute value of each one of matrixes elements public void abs(){ for (int i = 0; i < this.nrow; i++){ for (int j = 0; j < this.ncol; j++){ this.matriz[i][j] = Math.abs(this.matriz[i][j]); } } } // Retorna o exponencial de cada elemento da matriz. // Return the exponential value of each one of matrixes elements public void exp(){ for (int i = 0; i < this.nrow; i++){ for (int j = 0; j < this.ncol; j++){ this.matriz[i][j] = Math.exp(this.matriz[i][j]); } } } // Retorna o inverso de cada elemento da matriz. // Return the inverse value of each one of matrixes elements public void inverteElemento(){ for (int i = 0; i < this.nrow; i++){

44

Jos Iguelmar Miranda

for (int j = 0; j < this.ncol; j++){ this.matriz[i][j] = 1/this.matriz[i][j]; } } } // Adiciona um valor a cada elemento da matriz. // Add a value to each one of matrixes elements public void adiciona(double valor){ for (int i = 0; i < this.nrow; i++){ for (int j = 0; j < this.ncol; j++){ this.matriz[i][j] = this.matriz[i][j] + valor; } } } // Gradient calculation // Calcula gradiente da imagem // Parmetro: (Joo 7/8/2006) // dir = 1 ==> direo norte (north) // dir = 2 ==> direo sul (south) // dir = 3 ==> direo leste (east) // dir = 4 ==> direo oeste (west) public void gradiente(int dir) { double pReA, pReG; int lin, col; lin = this.nrow; col = this.ncol; switch(dir){ // direo norte para matriz e oeste para imagem // North for matrix and west for image case 1: for(int i = 0; i < col; i++){ for(int j = lin - 1; j > 0; j--){ pReA = this.matriz[j][i]; pReG = this.matriz[j-1][i];

45

Jos Iguelmar Miranda

this.matriz[j][i] = pReG - pReA; } } for(int i = 0; i < col; i++){ this.matriz[0][i] = 0.0; } break; // direo sul para matriz e leste para imagem // South for matrix and east for image case 2: for(int i = 0; i < col; i++){ for(int j = 0; j < lin - 1; j++){ pReA = this.matriz[j][i]; pReG = this.matriz[j+1][i]; this.matriz[j][i] = pReG - pReA; } } for(int i = 0; i < col; i++){ this.matriz[lin-1][i] = 0.0; } break; // direo leste para matriz e norte para imagen // East for matrix and north for image case 3: for(int i = 0; i < col - 1; i++){ for(int j = 0; j < lin; j++){ pReA = this.matriz[j][i]; pReG = this.matriz[j][i+1]; this.matriz[j][i] = pReG - pReA; } } for(int j = 0; j < lin; j++){ this.matriz[j][col-1] = 0.0; } break; // direo oeste para matriz e sul para imagem

46

Jos Iguelmar Miranda

// West for matrix and south for image case 4: for(int i = col - 1; i > 0; i--){ for(int j = 0; j < lin; j++){ pReA = this.matriz[j][i]; pReG = this.matriz[j][i-1]; this.matriz[j][i] = pReG - pReA; } } for(int j = 0; j < lin; j++){ this.matriz[j][0] = 0.0; } break; } } // Imprime a matriz com 'decimais' casas decimais // Print matrix with 'decimals' decimals public void imprimeMatriz(int decimais) { String padrao = "#."; for (int i = 0; i < decimais; i++) padrao += "#"; DecimalFormat formato = null; formato = new DecimalFormat(padrao); String elemento; System.out.println(); if (this.matriz == null){ System.out.println("Matriz vazia."); } else { int nr = this.getNrow(); int nc = this.getNcol(); for (int i = 0; i < nr; i++){ for (int j = 0; j < nc; j++){ elemento = formato.format(this.matriz[i][j]);

47

Jos Iguelmar Miranda

System.out.print(elemento+ "\t"); } System.out.println(); } } } } // end of Matriz

Source code is also available in the site:


http://repositorio.agrolivre.gov.br/projects/pid.

Look for CT_072_06. Please note: if you intend to use this material in any publication, please give credits to: MIRANDA, J. I.; CAMARGO NETO, J. Modelo de difuso anisotrpica para deteco de bordas. Campinas: Embrapa Informtica Agropecuria, 2006. Pginas: 4 (Embrapa Informtica Agropecuria. Comunicado Tcnico, 72). Available in: <http://www.cnptia.embrapa.br/files/ct72.pdf>. FOR ANY additional information, please contact: miranda@cnptia.embrapa.br

Bibliography
PARKER, J. R. Algorithms for image processing and computer vision. New York, NY: John Wiley & Sons, 1997. 417 p. CHUNG, D. H.; SAPIRO, G. S. Segmenting skin lesions with partial differential equations based image processing algorithm. IEEE Transactions on Medical Imaging, 19(7):763767, 2000. PERONA, P.; MALIK, J. Scale-space and edge detection using anisotropic diffusion. IEEE Transactions on Patterns Analysis and Machine Intelligence, 12(7):629-639, 1990.

48

Jos Iguelmar Miranda

DEMIRKAYA, O. Anisotropic diffusion filtering of PET attenuation data to improve emission images. Physics in Medicine and Biology, 47:271-278, 2002. GIBOU, F. et al. Partial differential equations-based segmentation for radiotherapy treatment planning. Mathematical Biosciences and Engineering, 2(2):209-226, 2005. KARANTZALOS, K. G.; ARGIALAS, D. P. Towards automatic olive tree extraction from satellite imagery. Istanbul, ISPRS 2004 12-23 July 2004, Congress title: Geo-Imagery Bridging Continents, XXth ISPRS Congress, 12-23 July 2004 Istanbul, Turkey. KOENDERINK, J. J. The structure of images. Biological Cybernetics, 50:363-370, 1984.

49

Você também pode gostar