UNIVERSIDAD DE CHILE Facultad de Ciencias Físicas y Matemáticas Departamento de Ciencias de la Computación CC3001-2 Algoritmos y Estructuras de Datos

INFORME TAREA 1: Detector Simple de Bordes

FECHA: NOMBRE: E-MAIL:

30-08-2010 Juan Carlos Sobarzo Ponce jsobarzo@ing.uchile.cl

Mediante el lenguaje de programación Java. y aplicando a ésta una serie de transformaciones que permitan obtener finalmente la imagen con los bordes detectados.INTRODUCCIÓN El presente informe desarrolla una solución al problema planteado en la tarea. En el caso de Matlab. pero con las facilidades que este lenguaje implica. que consiste en construir un programa que implemente un algoritmo básico de detección de bordes en una imagen. se diseñaron funciones para controlar las operaciones entre matrices y vectores. se implementó un algoritmos similar. en la importación de imágenes. llevándolo a una matriz que representa una imagen. . que en éste lenguaje se pueden implementar a partir de arreglos de números. así como en el tratamiento de matrices y vectores. Para esto. se busca programar un método que lea un archivo de texto.

Esta matriz se transforma en una matriz de MxN en tonalidad gris. Así también. cuyas componentes tras ser comparadas con un parámetro ingresado por el usuario. pero con la diferencia de que la importación se realiza directamente de la imagen. como del kernel a utilizar. Se supone que el ingreso.ANÁLISIS DEL PROBLEMA El problema consiste en implementar. se propone definir métodos que realicen cada uno de los pasos estipulados anteriormente. y luego las siguientes contienen los datos dados por el tamaño. de manera que su primera linea contiene los números que representan el tamaño de la imagen. en los lenguajes Java y Matlab. para luego aplicarle una convolución con los kernels decididos por el usuario. que se crean como arreglos de números. el parametro de gradiente y el nombre del archivo de salida. deben tener un formato correcto y acorde con los solicitado el ejecutar el programa. Dicho archivo debe ser llevado a una matriz de tamaño MxNx3. mediante coeficientes aplicados a cada componente de cada pixel. obtenipendose finalmente la matriz con los bordes detectados. . se definen métodos relacionados con el tratamiento de matrices. de manera que el programa principal pueda llamarlos cuando sea necesario. un algoritmo de detección de bordes en imágenes. Posteriormente se debe calcular el gradiente de la matriz en tonalidad gris. tanto del nombre de archivo. para cada componente por pixel. que corresponden a distintos tipos de filtro. que contiene la información de colores de la imagen. y el resultado final. se asume la importación de un archivo de texto que representa una imagen RGB. En Matlab se espera el mismo resultado. Para abordar el problema. En java. se presenta también como la imagen con los bordes destacados. son cambiadas por 1 o 0 dependiendo de si son mayores o menores que el parámetro.

el nombre del archivo de entrada. for (k=0. para luego almacenarla en un arreglo de Strings mediante la función split. int N=Integer.j++){ Foto[i][j][k]=Double. En cada ciclo del segundo for.i++) { linea=archivo. los kernels a utilizar. a partir de las convoluciones de ésta con los kernels seleccionados. – Se calculan los bordes de G.SOLUCIÓN El algoritmo de solución consiste en: – Se solicitan al usuario. aux2=linea. int i. int M=Integer. y luego transformar cada elemento en double y guardarlo en la matriz de salida. public double[][][] readMatrix(String filename) throws IOException { BufferedReader archivo=new BufferedReader(new FileReader(filename)). Dado el formato del archivo.parseInt(aux1[0]).k<3. while (linea. String linea=archivo.j. – Se calcula el gradiente de la matriz G. vía ventana de comandos. } linea=linea. – Se transforma la matriz RGB en una matriz G en tonalidades grises.readLine(). se implementaron los siguientes métodos: – Lectura de Matriz: Retorna un arreglo 3D de MxNx3. almacenandola en un arreglo de MxNx3. – Se lee la matriz en formato RGB desde el archivo de texto. se realiza primero la lectura de la primera línea.trim(). se lee una linea del archivo.equals("")) { linea=archivo. String[] aux1=linea.j<N. for (j=0. } } .readLine().trim().k. se ejecutan 3 ciclos for anidados. Luego. while (linea.split(" "). } linea=linea. String[] aux2=new String[N].parseInt(aux1[1]).readLine(). a partir de la lectura del archivo especificado por el nombre ingresado en el argumento. Bajo estas circunstancias.i<M. a partir del gradiente y del parámetro ingresado. que representa la imagen de entrada. double[][][] Foto=new double[M][N][3].readLine(). el parámetro de gradiente y el nombre del archivo de salida.parseDouble(aux2[j]). – Finalmente. que representan las 3 dimensiones de la matriz de salida.equals("")) { linea=archivo. se guarda en un archivo de texto la matriz resultante. que indica el tamaño de la matriz de salida.k++) { for (i=0.split(" ").

de MxN.length. int M=RGB. que retorna una especie de producto punto a punto pero en arreglos 2D. public double[][] convolution(double[][] A.j++) { FotoBN[i][j]=0. C[i][j]=termAterm(AUX. } .length. } – Convolución: Retorna un arreglo de (m-p+1)x(n-q+1). int n=A[0].j<N.i++) { for (j=0. double[][] FotoBN=new double[M][N]. Usa el método auxiliar copyMatrix.length. que copia un segmento de un arreglo dado. int q=B[0].i+p-1. int N=RGB[0]. que corresponde a la convolución del arreglo A (tamaño mxn) con el arreglo B (tamaño pxq). for (i=0.j. } } return FotoBN. public double[][] color2gray(double[][][] RGB) { int i.11*RGB[i][j][2]. } else if (m>=p&&n>=q){ for (i=0.59*RGB[i][j][1]+0.} archivo. que corresponde a la versión en gris de la imagen original. int p=B.close(). double[][] C=new double[r][s]. int r=m-p+1.length. int i. return Foto. if (m==p&&n==q) { C[0][0]=termAterm(A.length.i<M.j<s.j++) { AUX=copyMatrix(A.3*RGB[i][j][0]+0. int s=n-q+1.length.j.j.B).i++) { for (j=0. y lo retorna. } } } return C.double[][] B) { int m=A. double[][] AUX=new double[p][q].j+q-1).B).i. además del método termAterm. } – Matriz en Tonalidades Grises: Retorna un arreglo 2D.i<r.

length.2)). Operador de Prewitt (2). int m=A. int m=C1.double[][] M2) { double[][] C1=convolution(A.– Gradiente: Retorna el Gradiente del arreglo A. int n=A[0].length.j++) { G[i][j]=Math. public double[][] border(double[][] A.pow(C2[i][j].j. String kernel = readKeyb("Decida el kernel a utilizar.j<n. que permite el ingreso de información desde la ventana de comandos.j.length. double[][] C2=convolution(A.txt :"). tras aplicar la convolución de éste con los arreglos (kernels) M1 y M2 public double[][] gradient(double[][] A. int i.j++) { if (A[i][j]<grad) { A[i][j]=0. Incluye además la llamada de un método readKeyb. } else { A[i][j]=1.i<m. double[][][] PicRGB=readMatrix(nombrein).sqrt(Math. } – Bordes: Asigna el valor 0 a cada elemento cuyo gradiente sea menor que el parámetro grad.pow(C1[i][j].double[][] M1.M2). int n=C1[0]. entre Cruz de Robert (1). con los métodos explicados en esta sección. String nombreout = readKeyb("Ingrese el nombre del archivo de salida :"). String gradte = readKeyb("Ingrese el parametro de gradiente :"). } – Detección de Bordes: Ejecuta el algoritmo como se definió anteriormente.j<n. o 1 en caso contrario.double grad) { int i. double[][] G=new double[m][n]. } } } return A. for (i=0. ej: miarchivo. public void borderDetection() { try { String nombrein = readKeyb("Ingrese el nombre de archivo de entrada. } } return G.i<m.i++) { for (j=0. u Operador de Sobel (3) :").i++) { for (j=0.length.M1). for (i=0.2)+Math. .

printMatrix(Bordes. printMatrix(Bordes. } else if (kernel. double[][] Gradiente=gradient(PicG.M2). double[][] Bordes=border(Gradiente.0. mediante la instrucción: javac Tarea1.M2).java Luego.double[][] PicG=color2gray(PicRGB). printMatrix(Bordes.0.M1.kernel.0.nombreout).grad).{0.1}}.jpg'.{-1.1}}. double[][] Bordes=border(Gradiente.{-2.2. 2 o 3.0.java.{0.equals("3")) { double[][]M1={{-1.-1.{1.M2).1}. double[][] M2={{-1.0. double[][] Gradiente=gradient(PicG.out.equals("1")) { double[][] M1={{0.0}.{-1.grad) con kernel entre los valores 1.0}}. } else if (kernel.0. if (kernel.parseDouble(gradte).M1.1}. double[][] M2={{1. } } catch (IOException x) { System. double[][] Gradiente=gradient(PicG.{1.grad). Para ejecutar el programa en matlab. double grad=Double. se debe compilar en el directorio donde se encuentra el archivo Tarea1.println("ERROR").1.-1}}.-2.1}. y grad un número desde 1 a 255.nombreout).grad). } } Para ejecutar el programa en java.equals("2")) { double[][] M1={{-1.0}.-1}.1}. double[][]M2={{-1.1}}.{-1.-1}. se debe ejecutar escribiendo: java Tarea1 siguiendo las instrucciones dadas por el programa en sí.0. se debe escribir en la ventana de comandos la instrucción: detectarBordes('mifoto.{-1.nombreout). .M1.{0.0}.2}.0.1}}. double[][] Bordes=border(Gradiente.

Figura 1: Kernel=Cruz de Robert . A continuación se presentan los resultados.RESULTADOS Se probó el programa en java y matlab.Gradiente=50 . utilizando los distintos kernels y distintos valores de grad.Gradiente=10 Figura 2: Kernel=Cruz de Robert .

Gradiente=10 .Gradiente=100 Figura 4: Kernel=Operador de Prewitt .Figura 3: Kernel=Cruz de Robert .

Gradiente=50 Figura 6: Kernel=Operador de Prewitt .Gradiente=100 .Figura 5: Kernel=Operador de Prewitt .

Gradiente=10 Figura 8: Kernel=Operador de Sobel .Gradiente=50 .Figura 7: Kernel=Operador de Sobel .

pues aunque el de Sobel también tiene buenos resultados. . La Cruz de Robert no permite un buen trabajo. que a un mayor valor de gradiente. Así también. no se distinguen los bordes adecuadamente.Gradiente=100 Se observa de los resultados. pues para valores bajos del parámetro.Figura 9: Kernel=Operador de Sobel . el filtrado es más fino. permite mucho ruido. el primero alcanza una mayor claridad para un mismo valor de gradiente. se reconoce que el kernel más efectivo (en cuanto a nitidez y calidad) es el Operador de Prewitt. y para valores altos.

length. int m=Matrix. int i. int p=B.j<n. } } return Copia. for (i=0. int q=B[0].i<m.j++) { Copia[i][j]=Matriz[xfrom+i][yfrom+j].out.length.j<n.int xfrom.i<m.int yto) { int i.int yfrom.String filename) throws IOException { PrintWriter archivo=new PrintWriter(new FileWriter(filename)). } archivo. for (i=0.int xto.j++){ archivo.close(). } } return P. for (i=0. String linea=archivo.readLine().length.j.equals("")) { linea=archivo. } public void printMatrix(double[][] Matrix. } public double[][][] readMatrix(String filename) throws IOException { BufferedReader archivo=new BufferedReader(new FileReader(filename)). int n=Matrix[0].print(""+Matrix[i][j]+" ").j++) { P+=(A[i][j]*B[i][j]).j.*. int n=(yto-yfrom)+1.println("error de dimensiones").readLine(). while (linea. int i.ANEXOS Codigo Fuente JAVA: import java.length. double P=0. } public double termAterm(double[][] A. int n=A[0].trim().i++) { for (j=0.io.j<n. if (m!=p||n!=q) { System. } int i.double[][] B) { int m=A.length. class Tarea1 { public double[][] copyMatrix(double[][] Matriz.j.i++) { for (j=0. .length. double[][] Copia=new double[m][n]. } archivo. } linea=linea. int m=(xto-xfrom)+1.i<m.println("").i++){ for (j=0. int j.k.

double[][] C2=convolution(A. while (linea.M1).j<N. int p=B. } } } archivo.String[] aux1=linea. .equals("")) { linea=archivo.j<s. } } return FotoBN.j++){ Foto[i][j][k]=Double.readLine().i<r.length.length. int N=Integer.length.M2).i. int M=Integer.parseDouble(aux2[j]). double[][] C=new double[r][s].i<M.j.11*RGB[i][j][2]. double[][] AUX=new double[p][q]. C[i][j]=termAterm(AUX.j++) { AUX=copyMatrix(A. int m=C1. int n=C1[0]. aux2=linea.length.i<M.i+p-1.j+q-1). int M=RGB. for (i=0.3*RGB[i][j][0]+0.i++) { for (j=0. int N=RGB[0].B).close().B).readLine(). int n=A[0]. } } } return C. for (j=0.i++) { linea=archivo.k<3.parseInt(aux1[1]).j++) { FotoBN[i][j]=0.trim(). String[] aux2=new String[N].split(" ").j<N. double[][] FotoBN=new double[M][N].length. int s=n-q+1. } public double[][] convolution(double[][] A. return Foto. } else if (m>=p&&n>=q){ for (i=0. } linea=linea.length.double[][] M1.length. } public double[][] gradient(double[][] A.split(" "). int i.double[][] B) { int m=A.j. if (m==p&&n==q) { C[0][0]=termAterm(A.parseInt(aux1[0]).k++) { for (i=0.length.double[][] M2) { double[][] C1=convolution(A.59*RGB[i][j][1]+0. } public double[][] color2gray(double[][][] RGB) { int i.j. double[][][] Foto=new double[M][N][3]. int r=m-p+1.i++) { for (j=0. int q=B[0]. for (k=0.

0. u Operador de Sobel (3) :").sqrt(Math. double[][] Gradiente=gradient(PicG. printMatrix(Bordes. System.equals("1")) { double[][] M1={{0. } public String readKeyb(String mensaje) throws IOException { BufferedReader teclado = new BufferedReader(new InputStreamReader(System.-1}}.0.M2). ej: miarchivo.out.i<m.{0.length.0.grad).-1}. } else if (kernel. for (i=0.txt :").{-1.j. for (i=0.0. } .1}}. double[][][] PicRGB=readMatrix(nombrein). double[][] Bordes=border(Gradiente.2}.println(mensaje).i++) { for (j=0.i++) { for (j=0.1}}. double grad=Double.{0.double grad) { int i.equals("2")) { double[][] M1={{-1.i<m.0.0.2)). double[][] M2={{1.-1.{0.1}.readLine(). double[][]M2={{-1.0}.1}}.in)).{1.2)+Math.{-1. int m=A.M1.grad).1}}.0}. String gradte = readKeyb("Ingrese el parametro de gradiente :").-1}.M2).pow(C1[i][j].2. String entrada = teclado.M1. return entrada. String nombreout = readKeyb("Ingrese el nombre del archivo de salida :").M2).{-1. } } return G.pow(C2[i][j]. int n=A[0]. } else if (kernel. double[][] Gradiente=gradient(PicG.1.int i.nombreout). printMatrix(Bordes.j++) { G[i][j]=Math.1}.1}.0.grad).length. } else { A[i][j]=1.0}}.0}.nombreout). double[][] PicG=color2gray(PicRGB). } } } return A. double[][] Gradiente=gradient(PicG. printMatrix(Bordes. double[][] G=new double[m][n].1}.-2.M1.j.j<n. double[][] Bordes=border(Gradiente. Operador de Prewitt (2).equals("3")) { double[][]M1={{-1.{-1.parseDouble(gradte). double[][] M2={{-1.j<n. String kernel = readKeyb("Decida el kernel a utilizar. } public double[][] border(double[][] A.{-2. if (kernel. } public void borderDetection() { try { String nombrein = readKeyb("Ingrese el nombre de archivo de entrada.{1.nombreout). entre Cruz de Robert (1).j++) { if (A[i][j]<grad) { A[i][j]=0.0. double[][] Bordes=border(Gradiente.

} catch (IOException x) { System.out. } } . obj. } } static public void main(String[]args) throws IOException{ Tarea1 obj=new Tarea1().borderDetection().println("ERROR").

:.0.0.M2).0.1. end end end imshow(I) . G=(C1.0].0.0.na]=size(A).0. M2=[1. elseif kernel==2 M1=[-1.-2.Codigo Fuente MATLAB: function C=convolucion(A.11.-1.1. M2=[-1. for i=1:mi for j=1:ni if I(i.0.0.1.0.1)+0.j:(j+nb-1))).-2.^(1/2).-1. end G=0.-1. [mb. AB=zeros(mc.-1.j)=0.*RGB(:.0.0.-1.0].0.0.0.-1.0.0.0.j)<grad I(i. end end C=AB.0.*double(B))). M2=[-1.1.0.3.1.j)=sum(sum(double(A(i:(i+mb-1).0.0.0.0.0.M1.0.0.0.0.0. elseif kernel==3 M1=[-1.0.0.0.M1.0.0.grad) RGB=imread(archivo).0.^2).*RGB(:.0.nb]=size(B).0.M2) C1=convolucion(A.0].0].M1).0.2.:. else I(i. for i=1:mc for j=1:nc AB(i. C2=convolucion(A.nc).0. function detectarBordes(archivo.0].^2+C2.0.0.1.0.-1. [mi.B) [ma. if kernel==1 M1=[0.0.2.0. nc=na-nb+1.0.-1. I=gradiente(G.*RGB(:.0.:.1.1.0.M2).59.2)+0.1.0.0.3). function G=gradiente(A.0.0].1.j)=1.ni]=size(I).1. mc=ma-mb+1.0.0.kernel.0.

Sign up to vote on this title
UsefulNot useful