Informe técnico final de proyecto “Evaluación de resultados

Anuncio
Informe técnico final de proyecto “Evaluación de resultados de una propuesta
constructivista para la enseñanza de la programación”.
Clave SIP: 20070597.
Ramón Sebastián Salat Figols.
Resumen.
En este proyecto se presentan los resultados obtenidos durante la impartición de un
curso de programación de computadoras a estudiantes de Física y de Matemáticas con
un enfoque en el que los conceptos se presentan durante la solución de problemas de
Matemáticas y de Física, procurando estimular la iniciativa del estudiante y la discusión
de los problemas entre ellos y con el profesor.
1. Introducción.
Las primeras computadoras electrónicas fueron construidas para resolver problemas de
administración, procesando datos de censos; de criptografía, codificando y
decodificando mensajes para fines militares; y de ciencias exactas, calculando
trayectorias de proyectiles. Hoy en día, con las computadoras pueden resolverse
problemas por medio de simulación de fenómenos; por ejemplo, pueden obtenerse
valores aproximados para la probabilidad crítica de percolación, Salat (2005).
Interesantes ejemplos del tipo de problemas de Matemáticas que pueden abordarse con
la computadora pueden encontrarse en Borwein, Bailey y Girgensohn (2004).
Los avances en hardware y en software permitieron que la computadora se convirtiera
en una herramienta indispensable en una buena parte del trabajo científico y la
programación de computadoras se volvió una materia fundamental en la formación
dentro de las ciencias exactas.
En la Escuela Superior de Física y Matemáticas del Instituto Politécnico Nacional, el
estudio de la materia de Programación I, pretende proveer a los estudiantes de una
herramienta para resolver problemas. Sin embargo, a pesar de que algunos egresados
han tenido un desarrollo profesional sobresaliente en el área de la computación, muchos
otros no logran una apropiación e instrumentación de la computadora como una
herramienta.
Thomson (1997), realiza un estudio en el que introduce el método de solución de
problemas en la enseñanza de la programación funcional y emplea el método propuesto
por Polya (1957) en la solución de los mismos. Villarreal (2005), estudia el trabajo de
profesores de enseñanza media en matemáticas, en relación a la metodología de
solución de problemas y uso de las tecnologías informáticas de la comunicación.
El objetivo del presente estudio es el de obtener evidencia experimental acerca de los
resultados que se obtienen en un curso de programación en lenguaje C, presentado los
diferentes elementos sintácticos del lenguaje en el contexto de diversos problemas de
Física y de Matemáticas, propiciando la discusión de los problemas en clase entre los
alumnos y con el profesor. El estudio se realiza con un grupo de la materia de
Programación I de alumnos de la carrera de Licenciado en Física y Matemáticas.
Primero se presentarán datos acerca hasta qué punto saben programar para resolver
problemas los alumnos que ya cursaron la materia y después, los del estudio
propiamente.
2. Datos preliminares.
A estudiantes que cursan la materia de Estadística I y que ya cursaron la materia de
Programación I se les propuso el siguiente problema:
Dado un conjunto de n datos x1 , x2 , x3 ,..., xn , se definen:
x + x 2 + x 3 + ...+ x n
.
a) La media, x media = 1
n
b) La desviación estándar, σ =
(x1 − x media ) + (x 2 − x media )
2
2
+ ...(x n − x media )
2
.
n
Escribir el código de un programa en computadora que admita como datos de entrada n
y los datos x1 , x2 ,..., xn , y que dé como resultados la media y la desviación estándar.
De catorce alumnos solamente cuatro intentaron el problema. Dos de ellos lo hicieron
en un lenguaje diferente de C y solamente un alumno respondió con un programa en C
bien organizado, es decir, usando funciones y con un código que se lee con facilidad.
Estos datos muestran que de los catorce alumnos, diez de ellos ni siquiera intentaron
responderlo.
El mismo problema se aplicó a dieciocho estudiantes del curso de Programación I,
después de siete semanas de iniciado (la duración total es de dieciocho semanas). En
este caso, solamente cinco de dieciocho alumnos no atacaron el problema. De los trece
que respondieron, tres presentaban fallas en la sintaxis, seis presentaban fallas en la
obtención del resultado, once elaboraron un programa ordenado y ocho usaron
funciones.
En resumen, en el grupo de Estadística I que ya habían cursado Programación I, el 28.6
% respondió el reactivo, mientras que en grupo que estaba cursando Programación I, lo
resolvieron 72.2 %. Los resultados se resumen en la Tabla 1.
Grupo que cursaba
programación.
Obtuvieron el programa.
11
No obtuvieron el programa.
7
Total de alumnos.
18
Tabla 1.
Grupo que ya cursó
programación.
4
10
14
Dado que el problema es un ejercicio de programación sencillo, puede afirmarse que la
mayoría de los alumnos que ya habían cursado Programación I, tenían dificultades para
crear programas sencillos, mientras que en el grupo que estaba cursando Programación
I, la mayoría podían realizar tareas sencillas de programación en C.
2. Desarrollo del curso.
El curso tiene una duración total de 18 semanas y se imparte en tres sesiones por
semana de cuatro horas y media, cada una. La primera sesión de la semana, se desarrolla
en el laboratorio de cómputo, de manera que cada alumno tiene una computadora a su
disposición.
La orientación del curso tuvo las siguientes características:
a) Los diferentes elementos de la sintaxis del lenguaje C fueron presentados en el
contexto de la solución de algún problema de Matemáticas.
b) En la mayoría de los casos, se planteaba el problema y se permitía que los
alumnos trabajaran en él, con la dirección del profesor. Cuando el profesor
presentaba un programa ya elaborado, se les dejaba a los alumnos tareas
relativas al mismo problema que implicaban la modificación o reelaboración del
programa.
c) Se procuró estimular constantemente la participación y discusión entre los
alumnos y con el profesor en la solución de los problemas.
.
Durante las primeras 7 semanas del curso, se introdujeron los diferentes elementos
sintácticos del lenguaje C, mientras se resolvían problemas como los siguientes:
a) Elaborar una tabla para convertir grados Fahrenheit a grados centígrados.
b) Elaborar una tabla de la altura que cae un cuerpo como función del tiempo.
El problema a) se resolvió en clase y el b) se dejó para que lo hicieran los alumnos.
c) Resolver una ecuación diferencial ordinaria, no lineal, numéricamente.
En este problema c), se llegó al método de aproximación pensando que la curva
solución era la función distancia contra tiempo para el movimiento de una partícula
y aproximando el movimiento localmente como un movimiento uniformemente
acelerado.
d) Dado un número natural, encontrar el número de números primos menores que
él.
Se pidió a los estudiantes que investigaran si había alguna relación entre el número
natural y el número de primos menores que él y se le invitó a investigar en la
bibliografía.
e) Aproximar el valor de π por varios métodos.
Entre ellos, el de simular el lanzamiento de un gran número de dardos y observar
que fracción caen dentro del área que se quiere calcular.
f) Simular n lanzamientos de un dado y determinar las frecuencias relativas de
los diferentes resultados posibles.
g) Encontrar el ángulo para el cual cierta parte del sector circular
correspondiente, tenga un área dada.
Este problema conduce a resolver una ecuación trascendente. Se discutieron con los
alumnos los métodos de bisección, de Newton y de punto fijo, recordando conceptos
que ya habían aprendido en Cálculo.
h) Calcular la mediana de un conjunto de datos.
Este problema requiere que se ordenen los datos.
i) Simular la expansión de un incendio forestal.
Se divide el bosque en n × n celdas, cada una de las cuales solamente puede estar en
estado 0 (vacía), 1 (ocupada por un árbol que no se ha incendiado), 2 (ocupada por
un árbol que está encendido) y 3 (ocupada por un árbol que ya se quemó y que está
apagado). Si en una celda hay un árbol apagado y en alguna de las celdas vecinas
hay alguno encendido, entonces en el siguiente intervalo de tiempo, el árbol se
prende. Si un árbol está prendido, en el siguiente intervalo de tiempo, el árbol se
apaga. Simulando incendios forestales, se puede estudiar bajo qué condiciones el
incendio se propaga de un lado al otro del bosque, por ejemplo.
La resolución de problemas en Matemáticas tiene características generales de manera
que se pueden aplicar principios también de carácter general. Pero cuando la solución
que se busca implica la elaboración de un programa en computadora, entonces se
presenta por lo menos una característica importante específica. Para poder definir una
serie de instrucciones que tiene que efectuar la computadora, se tiene que tener
perfectamente claro el algoritmo. Durante la resolución de los problemas se insistió en
que antes de escribir el código, el alumno se pregunte si el podría efectuar las
operaciones con papel y lápiz, al menos en principio.
En algunos casos, el profesor resolvió el problema en clase y pidió a los alumnos la
solución de un problema similar; en otros, se resolvió el problema en clase dando la
iniciativa al alumno; y en otros más, simplemente se dejó a que el alumno resolviera el
problema sin la intervención del profesor.
3. Un examen más complejo.
Dos clases después de la aplicación del examen anterior, se aplicó el siguiente examen a
28 alumnos del grupo que cursaba Programación I.
Para cada programa hay que entregar el listado del código del programa y el resultado
que obtuvo.
x2
1 −
1
e 2 dx con cuatro cifras decimales.
1. Calcular la integral
∫
0
2π
2. Encontrar la abscisa del punto de intersección de las curvas y = x 2 y y = sen x
diferente del origen de coordenadas.
Respecto al primer problema, de los 28 alumnos, 15 lograron escribir el código del
programa; pero solamente 7 de estos 15, lograron obtener la respuesta numérica
correcta. Para el problema 2, de los 28 alumnos, 9 pudieron escribir el código del
programa y todos ellos obtuvieron la respuesta correcta. De los 28 alumnos, 6 no
pudieron hacer nada en el problema 1, mientras que 10 no pudieron hacer nada en el
problema 2. Los resultados se resumen en la tabla 2.
Escribieron el código
Obtuvieron la respuesta
No escribieron nada
Total de alumnos
Problema 1
15
7
6
28
Tabla 2
Problema 2
9
9
10
28
Como puede observarse de los datos, en este caso, los resultados no son tan buenos
como en el caso del examen preliminar. Esto era de esperarse ya que los problemas de
este examen son más difíciles que el problema del examen preliminar. En los problemas
de este examen había que descubrir primero el algoritmo que había que aplicar y luego,
construir el programa, mientras que en el examen preliminar, el algoritmo ya estaba
definido y era más sencillo.
En la última parte del curso, se les presentó un programa escrito utilizando clases y
utilizando la biblioteca winbgim, para simular el movimiento browniano. A los
alumnos, en general les pareció interesante la simulación gráfica. Surgió la discusión de
que el modelo que se utilizó para diseñar el programa no consideraba el choque entre las
partículas. Entonces se planteó el problema de diseñar un programa que simulara el
movimiento de n bolas con el mismo radio (en dos dimensiones) considerando choques
entre ellas. En clase se recordaron las ideas básicas que ellos ya conocían acerca de
choque inelástico, de la conservación de la energía cinética y del momento, para
modelar el choque entre ellas.
Un alumno entregó el programa a los dos días, aunque tenía una falla, ya que en
ocasiones, las bolas se traslapaban. Otros tardaron más días pero también lo hicieron
con la misma falla. Y alrededor de una cuarta parte no pudieron hacerlo. Para los
alumnos que lograron hacerlo resultó un ejercicio muy motivante; se pusieron a trabajar
fuerte para descubrir sus errores y corregirlos.
Debido a la heterogeneidad del grupo algunos problemas tienen un efecto muy distinto
en los alumnos. Por ejemplo, el problema de las bolas, para unos fue muy motivante,
mientras que para otros no significó nada en cuanto a actividades de aprendizaje
realizadas.
4. Análisis de los datos y conclusiones.
Los datos del examen preliminar apoyan la hipótesis de que un enfoque de la enseñanza
de la programación basada en solución de problemas, mejora los resultados que se
obtienen con un enfoque tradicional, donde el profesor explica los conceptos, resuelve
ejemplos y deja ejercicios. Los alumnos de Programación I, resolvieron el examen
preliminar mucho mejor que el segundo examen. Es decir, cuando la dificultad de la
tarea aumenta, los resultados no son tan buenos. Una interpretación posible a este
hecho es que siete semanas es poco tiempo para que los estudiantes acostumbrados al
sistema tradicional se adapten al nuevo sistema; y aún el mismo profesor puede tener
dificultades para asumir plenamente el nuevo enfoque.
Pero hay otra razón muy importante. Si se entiende el curso de programación como para
que los estudiantes escriban programas dados los algoritmos que hay que programar,
entonces la tarea es relativamente sencilla y también poco ambiciosa. Pero si se entiende
el curso de programación como un esfuerzo para que los estudiantes instrumenten y se
apropien de la programación como una herramienta para resolver problemas de
Matemáticas y de Física, entonces la tarea es más difícil, ya que implica un avance en
las estrategias de los alumnos para resolver problemas.
El planteamiento de problemas más complejos, produce resultados diferentes en los
alumnos; para unos, el problema es demasiado difícil de resolver; para otros es muy
motivante y desencadena en ellos una actividad cognitiva importante.
Un asunto importante que se dejó de lado en este proyecto es el de que problemas
pueden ser más interesantes para los alumnos. Por ejemplo, los programas que se
desarrollan son programas para ejecutarse en la línea de comandos y a lo más algunos
gráficos, pero no se estudia programación en un entorno con ventanas, cuando en
realidad este tipo de programas son los más frecuentemente utilizados por los usuarios
de las computadoras.
Referencias.
1. Borwein, J.; Bailey, D.; Girgensohn, R. (2004).
Experimentation in Mathematics. Computational Paths to Discovery.
A.K. Peters.
2. Salat, Ramón (2005).
El fenómeno de la percolación.
Miscelánea Matemática. Revista de la Sociedad Matemática Mexicana.
Número 41. Agosto/05.
3. Schoenfeld, A.H. (1985)
Mathematical Problem Solving.
Academic Press.
4. Polya, George (1957)
How To Solve It.
Princeton University Press, 2nd Edition
5. Thompson, Simon (1997)
‘Where do I begin? A problem solving approach in teaching functional programming’
First International Conference on Declarative Programming Languages in Education,
Krzysztof Apt, Pieter Hartel, Paul Klint (editors) Springer-Verlag
6. Villarreal, Gonzalo (2005)
La resolución de problemas en matemática y el uso de las TIC: resultados de un estudio
en los colegios de Chile.
Edutec. Número 19. Julio/05.
Anexo. Código para el programa que simula el movimiento de n bolas que chocan entre
sí.
//Ramon Sebastián Salat Figols. ESFM. Noviembre de 2007.
#include <winbgim.h>
#include <stdio.h>
#include <stdlib.h>
#include<math.h>
#define R 20
#define N 10
int MAXX=800;
int MAXY=600;
float e=.01;
main()
{
float x1,y1,vx1,vx2,vy1,vy2,rx,ry,vt1,vt2,vn1,vn2,tx,ty,nx,ny,t,a,b,o=6.;
int i,j,k,indi,iter=0,d;
float xa1,ya1;
float x[N],y[N],vx[N],vy[N],xa[N],ya[N],xt[N],yt[N];
d=(int)(1./e);
initwindow(MAXX,MAXY);
setcolor(WHITE);
for(i=0;i<N;i++)
{
x[i]=(float)(2*MAXX);
y[i]=(float)(2*MAXY);
}
for(i=0;i<N;i++)
{
indi=1;
while(indi==1)
{
a=(float)(rand()%(MAXX-2*R-2)+R+1);
b=(float)(rand()%(MAXY-2*R-2)+R+1);
indi=0;
if(i>0)
{
for(j=0;j<i;j++)
{
if((x[j]-a)*(x[j]-a)+(y[j]-b)*(y[j]-b)<(2*R+2)*(2*R+2))
indi=1;
}
}
}
x[i]=a;
y[i]=b;
xa[i]=x[i];
ya[i]=y[i];
vx[i]=1.1*(i%2-1);
vy[i]=1.1;
x1=x[i];
y1=y[i];
xt[i]=x1;
yt[i]=y1;
circle(x1,y1,R);
}
d=(int)(1/e);
while(!kbhit())
{
iter++;
if(iter%d==0)
{
setcolor(BLACK);
for(i=0;i<N;i++)
circle(xt[i],yt[i],R);
setcolor(WHITE);
for(i=0;i<N;i++)
circle(x[i],y[i],R);
for(k=1;k<4000000;k++);
for(i=0;i<N;i++)
{
xt[i]=x[i];
yt[i]=y[i];
}
}
for(i=0;i<N;i++)
{
x[i]=x[i]+e*vx[i];
y[i]=y[i]+e*vy[i];
xa[i]=x[i];
ya[i]=y[i];
if(x[i]-R<0)
vx[i]=-vx[i];
if(x[i]+R>MAXX)
vx[i]=-vx[i];
if(y[i]-R<0)
vy[i]=-vy[i];
if(y[i]+R>MAXY)
vy[i]=-vy[i];
if(i<N-1)
{
for(j=i+1;j<N;j++)
{
}
}
}
}
if(sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]))-2*R<0.)
{
rx=x[i]-x[j];
ry=y[i]-y[j];
a=rx;
b=ry;
rx=rx/sqrt(a*a+b*b);
ry=ry/sqrt(a*a+b*b);
tx=ry;
ty=-rx;
vn1=vx[i]*rx+vy[i]*ry;
vn2=vx[j]*rx+vy[j]*ry;
vt1=vx[i]*tx+vy[i]*ty;
vt2=vx[j]*tx+vy[j]*ty;
t=vn1;
vn1=vn2;
vn2=t;
vx[i]=rx*vn1+tx*vt1;
vy[i]=ry*vn1+ty*vt1;
vx[j]=rx*vn2+tx*vt2;
vy[j]=ry*vn2+ty*vt2;
}
}
closegraph();
Anexo 2. Software para disminuir el ruido en imágenes digitales (r01).
Proyecto “Evaluación de resultados de una propuesta constructivista para la
enseñanza de la programación”.
Clave SIP: 20070597.
Ramón Sebastián Salat Figols.
Manual para el uso del conjunto de programas para reducir el ruido en imágenes.
Introducción.
Los programas disminuyen el ruido substituyendo para cada píxel de la imagen la
intensidad de cada color (para el rojo, el verde y el azul) por el promedio de la
intensidad en los pixels vecinos. Los programas efectúan este cálculo solamente para los
pixels que corresponden a ruido y que no pertenecen a algún borde de la imagen y cuya
vecindad no contenga puntos de algún borde.
Para decidir si un punto puede considerarse ruido se calcula el promedio de las
intensidades de los colores para las celdas periféricas de una vecindad del punto y el
promedio de la intensidad de los colores para las celdas interiores a la vecindad. La
diferencia absoluta de estos dos promedios se toma como un indicador sobre el cual se
toma la decisión.
Para detectar los bordes se utiliza el parámetro dado por la varianza de las intensidades
de los colores de las celdas periféricas en una vecindad del punto.
Los programas funcionan sobre una imagen con terminación .bmp y de una resolución
de 3888x2592 , que corresponden a una imagen de 10 megapixels.
El paquete de consta de 6 programas. Cada uno de ellos puede ejecutarse
individualmente en la línea de comandos. O pueden ejecutarse de forma automática en
conjunto por medio de un archivo de procesamiento por lotes.
I. Versión para la línea de comandos.
a) El programa borde.exe.
Este programa requiere que la imagen esté en el mismo directorio en el que se está
ejecutando el programa y requiere de tres parámetros. El primero es un número
entero, de tal manera que si el parámetro que se utiliza para determinar el borde
tiene un valor mayor que el de este parámetro, entonces el píxel se considerará como
de ruido (los valores apropiados van desde 100 hasta 4000, aproximadamente, según
la imagen); el segundo parámetro es el número de capas de la vecindad que se
considera, las vecindades son cuadradas y el número de capas es la distancia del
centro a un píxel extremo menos uno (valores razonables son 3, 5, 7);el tercer
parámetro se refiere al método que se utilizará para detectar los bordes, el 1
corresponde a la varianza, un valor de 2 corresponde al uso del laplaciano.
El resultado de la ejecución del programa es un archivo Y.bmp en el mismo
directorio en el que se está ejecutando el programa.
b) El programa filtrado1.exe
Con frecuencia la imagen que se obtiene para los bordes (Y.bmp) contiene
conglomerados de pixels que no corresponden a bordes. El programa filtrado1.exe
usa un parámetro de tal modo que se borran todos los conglomerados cuyo número
de pixels sea menor que dicho parámetro. Valores razonables son 40, 50, 60,70.
Conforme el valor del parámetro crece, el tiempo de ejecución aumenta
notablemente. El programa produce un archivo Y1.bmp en el mismo directorio
donde se está ejecutando el programa.
c) El programa ruido.exe.
Este programa usa dos parámetros. El primero es un número entero tal que aquellos
pixels para los cuales el parámetro correspondiente sea mayor que el valor del
parámetro, se considerará como píxel de ruido. El segundo parámetro se refiere al
número de capas de la vecindad en la que se calcula el parámetro para detectar
ruido. El programa toma un archivo X.bmp y produce un archivo Y.bmp (X.bmp
debe estar en el mismo directorio en el que se está ejecutando el programa).
d) El programa suma.exe.
Este programa actúa sobre los archivos resultado de obtener los bordes filtrados y el
ruido. Construye un archivo bmp de tal manera que par cada píxel éste será blanco si
y solamente si el píxel correspondiente en la imagen correspondiente al ruido es
blanco y en la imagen correspondiente al borde el píxel es negro. El resultado es una
máscara, esto es, una imagen de fondo negro con pixels blancos para el caso en que
para este píxel sea necesario modificar la imagen original. El programa requiere de
la presencia de los archivos X.bmp y Y.bmp en el mismo directorio en el que se
ejecuta el programa y produce un archivo Z.bmp.
e) El programa mascara.exe.
Este programa toma como entrada al archivo de la imagen original como X.bmp, el
archivo de la máscara obtenido por suma.exe como Y.bmp y el archivo de bordes
filtrado como B.bmp y produce el archivo Z.bmp. Este programa modifica la
imagen original considerando la máscara producida por suma.exe cuidando no
considerar aquellos pixels cuya vecindad tenga algún punto de algún borde. Utiliza
el número de capas de la vecindad considerada para modificar la imagen original.
Con todos los programas ejecutables y el archivo original X.bmp en el directorio
c:/taller, se puede realizar todo el proceso de disminución del ruido con el archivo
total.bat con los siguientes seis parámetros en la línea de comandos: umbral para
determinar el borde, número de capas, método para determinar el borde, tamaño de
los objetos por filtrar, umbral para determinar el borde y nombre del subdirectorio
del directorio taller, en el que se efectuará todo el proceso. El archivo final es
Z.bmp, pero en el nuevo subdirectorio están todos los archivos que se crean durante
el proceso, para poder determinar si es conveniente cambiar alguno de los
parámetros.
A continuación se presenta el contenido del archivo total.bat:
@echo off
cls
md %6%1%2%3%4%5
copy X.bmp c:\taller\%6%1%2%3%4%5
copy borde.exe c:\taller\%6%1%2%3%4%5
copy ruido.exe c:\taller\%6%1%2%3%4%5
copy mascara1.exe c:\taller\%6%1%2%3%4%5
copy filtrado1.exe c:\taller\%6%1%2%3%4%5
copy suma.exe c:\taller\%6%1%2%3%4%5
cd c:\taller\%6%1%2%3%4%5
time/t
echo inicia borde
borde %1 %2 %3
echo inicia filtrado
filtrado1 %4
rename Y.bmp B.bmp
rename Y1.bmp BF.bmp
echo inicia ruido
ruido %5 %2
rename Y.bmp R.bmp
rename X.bmp O.bmp
copy R.bmp X.bmp
copy BF.bmp Y.bmp
echo inicia suma
suma
copy Z.bmp M.bmp
del X.bmp
del Y.bmp
rename O.bmp X.bmp
rename Z.bmp Y.bmp
rename B.bmp H.bmp
rename BF.bmp B.bmp
echo inicia mascara
mascara1 %2
del Y.bmp
rename B.bmp BF.bmp
rename H.bmp B.bmp
time/t
echo umbral borde %1
echo capas para borde %2
echo metodo para borde %3
echo parametro de filtrado %4
echo umbral ruido %5
del borde.exe
del filtrado1.exe
del suma.exe
del mascara1.exe
del ruido.exe
Código de borde
//Ramon Sebastian Salat Figols. Julio, 2007.
//Requiere dos parametros. El primero es el umbral para el borde y el segundo
//el numero de capas. El archivo de entrada es X.bmp y el de salida Y.bmp
//Usa como parametro la varianza de los pixels perifericos.
#include <cstdlib>
#include <iostream>
#include <fstream>
#include "biblioteca.h"
using namespace std;
int main(int argc,char * argv[]){
unsigned char c;
int i,j,k,l=0,capas,tipo;
float par2,umbral_borde;
unsigned char **imagen,**imagen_1;
imagen=new unsigned char*[MAXY];
imagen_1=new unsigned char*[MAXY];
ifstream X;
ofstream Y;
umbral_borde=atof(argv[1]);
capas=atoi(argv[2]);
tipo=atoi(argv[3]);
for(i=0;i<MAXY;i++){
imagen[i]=new unsigned char[3*MAXX];
imagen_1[i]=new unsigned char[3*MAXX];
}
X.open("X.bmp",ios::binary);
Y.open("Y.bmp",ios::binary);
for(i=0;i<54;i++){
c=X.get();
Y.put(c);
l++;
}
for(i=0;i<MAXY;i++){
for(j=0;j<3*MAXX;j++){
c=X.get();
imagen[i][j]=c;
imagen_1[i][j]=c;
}
}
for(i=capas;i<MAXY-capas;i++){
for(j=capas;j<MAXX-capas;j++){
if(tipo==1)
par2=varianza(i,j,0,imagen,capas)+varianza(i,j,1,imagen,capas)+varianza(i,j,2,imagen,capas);
if(tipo==2)
par2=laplace(i,j,0,imagen)+laplace(i,j,1,imagen)+laplace(i,j,2,imagen);
if(tipo==3)
par2=diferencia_simetrica(i,j,0,imagen)+diferencia_simetrica(i,j,1,imagen)+diferencia_simetrica
(i,j,2,imagen);
if(par2>umbral_borde){
for(k=0;k<3;k++){
imagen_1=modifica((unsigned char)254,i,j,k,imagen_1);
}
}
else{
for(k=0;k<3;k++){
imagen_1=modifica((unsigned char)0,i,j,k,imagen_1);
}
}
}
}
for(i=0;i<MAXY;i++){
for(j=0;j<3*MAXX;j++){
}
}
c=imagen_1[i][j];
Y.put(c);
l++;
}
X.close();
Y.close();
return 0;
Código de filtrado1.
//Ramon Sebastian Salat Figols. Julio, 2007.
//Requiere dos parametros. El primero es el umbral para el borde y el segundo
//el numero de capas. El archivo de entrada es X.bmp y el de salida Y.bmp
//Usa como parametro la varianza de los pixels perifericos.
#include <cstdlib>
#include <iostream>
#include <fstream>
#include "biblioteca.h"
using namespace std;
int main(int argc,char * argv[]){
unsigned char c;
int i,j,k,l=0,n,p,q,m,x,s;
unsigned char **imagen,**imagen_1;
imagen=new unsigned char*[MAXY];
imagen_1=new unsigned char*[MAXY];
ifstream Y;
ofstream Y1;
n=atoi(argv[1]);
for(i=0;i<MAXY;i++){
imagen[i]=new unsigned char[3*MAXX];
imagen_1[i]=new unsigned char[3*MAXX];
}
Y.open("Y.bmp",ios::binary);
Y1.open("Y1.bmp",ios::binary);
for(i=0;i<54;i++){
c=Y.get();
Y1.put(c);
l++;
}
for(i=0;i<MAXY;i++){
for(j=0;j<3*MAXX;j++){
c=Y.get();
imagen[i][j]=c;
imagen_1[i][j]=c;
}
}
imagen_1=filtrado_dos(n,imagen,imagen_1);
for(i=0;i<MAXY;i++){
for(j=0;j<3*MAXX;j++){
}
}
}
Y.close();
Y1.close();
return 0;
c=imagen_1[i][j];
Y1.put(c);
l++;
Código de mascara1.
//Ramon Sebastian Salat Figols. Julio, 2007.
//parametro: numero de capas para la modificacion.
//Requiere el archivo B.bmp del borde.
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <cstdlib>
#include "biblioteca.h"
using namespace std;
int main(int argc,char* argv[]){
unsigned char c,r,g,b;
int i,j,capas,h;
unsigned char **imagen_x,**imagen_y,**imagen_z,**imagen_b;
imagen_x=new unsigned char*[MAXY];
imagen_y=new unsigned char*[MAXY];
imagen_z=new unsigned char*[MAXY];
imagen_b=new unsigned char*[MAXY];
ifstream X;
ifstream Y;
ifstream B;
ofstream Z;
capas=atoi(argv[1]);
for(i=0;i<MAXY;i++){
imagen_x[i]=new unsigned char[3*MAXX];
imagen_y[i]=new unsigned char[3*MAXX];
imagen_z[i]=new unsigned char[3*MAXX];
imagen_b[i]=new unsigned char[3*MAXX];
}
X.open("X.bmp",ios::binary);
Y.open("Y.bmp",ios::binary);
B.open("B.bmp",ios::binary);
Z.open("Z.bmp",ios::binary);
for(i=0;i<54;i++){
c=B.get();
c=Y.get();
c=X.get();
Z.put(c);
}
for(i=0;i<MAXY;i++){
for(j=0;j<3*MAXX;j++){
c=B.get();
imagen_b[i][j]=c;
c=X.get();
imagen_x[i][j]=c;
imagen_z[i][j]=c;
c=Y.get();
imagen_y[i][j]=c;
}
}
for(i=capas;i<MAXY-capas;i++){
for(j=capas;j<MAXX-capas;j++){
h=(int)extrae(i,j,0,imagen_y)+(int)extrae(i,j,1,imagen_y)+(int)extrae(i,j,2,imagen_y);
if(h>760){
imagen_z=promedia_sb(i,j,imagen_x,imagen_z,imagen_b,capas);
}
else{
r=extrae(i,j,2,imagen_x);
g=extrae(i,j,1,imagen_x);
b=extrae(i,j,0,imagen_x);
imagen_z=modifica(r,i,j,2,imagen_z);
imagen_z=modifica(g,i,j,1,imagen_z);
imagen_z=modifica(b,i,j,0,imagen_z);
}
}
}
}
for(i=0;i<MAXY;i++){
for(j=0;j<3*MAXX;j++){
c=imagen_z[i][j];
Z.put(c);
}
}
X.close();
Y.close();
B.close();
Z.close();
return 0;
Código de ruido.
#include <cstdlib>
#include <iostream>
#include <fstream>
#include "biblioteca.h"
using namespace std;
int main(int argc,char * argv[]){
unsigned char c;
int i,j,k,l=0,capas;
float par1,umbral_ruido;
unsigned char **imagen,**imagen_1;
imagen=new unsigned char*[MAXY];
imagen_1=new unsigned char*[MAXY];
ifstream X;
ofstream Y;
umbral_ruido=atof(argv[1]);
capas=atoi(argv[2]);
for(i=0;i<MAXY;i++){
imagen[i]=new unsigned char[3*MAXX];
imagen_1[i]=new unsigned char[3*MAXX];
}
X.open("X.bmp",ios::binary);
Y.open("Y.bmp",ios::binary);
for(i=0;i<54;i++){
c=X.get();
Y.put(c);
l++;
}
for(i=0;i<MAXY;i++){
for(j=0;j<3*MAXX;j++){
c=X.get();
imagen[i][j]=c;
imagen_1[i][j]=c;
}
}
for(i=capas;i<MAXY-capas;i++){
for(j=capas;j<MAXX-capas;j++){
par1=parametro_1(i,j,0,imagen,capas)+parametro_1(i,j,1,imagen,capas)+parametro_1(i,j,2,imag
en,capas);
if(par1>umbral_ruido){
for(k=0;k<3;k++){
imagen_1=modifica((unsigned char)254,i,j,k,imagen_1);
}
}
else{
for(k=0;k<3;k++){
imagen_1=modifica((unsigned char)0,i,j,k,imagen_1);
}
}
}
}
for(i=0;i<MAXY;i++){
for(j=0;j<3*MAXX;j++){
c=imagen_1[i][j];
Y.put(c);
l++;
}
}
X.close();
Y.close();
return 0;
}
Código de suma.
//Ramon Sebastian Salat Figols. Julio, 2007.
//parametro 1: umbral ruido parametro 2: umbral borde
//parametros 3 4 y 5 numero de capas, para el ruido, para el borde y para
//la modificacion.
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <cstdlib>
#include "biblioteca.h"
using namespace std;
int main(){
unsigned char c;
int i,j,hx,hy,k;
unsigned char **imagen_x,**imagen_y,**imagen_z;
imagen_x=new unsigned char*[MAXY];
imagen_y=new unsigned char*[MAXY];
imagen_z=new unsigned char*[MAXY];
ifstream X;
ifstream Y;
ofstream Z;
for(i=0;i<MAXY;i++){
imagen_x[i]=new unsigned char[3*MAXX];
imagen_y[i]=new unsigned char[3*MAXX];
imagen_z[i]=new unsigned char[3*MAXX];
}
X.open("X.bmp",ios::binary);
Y.open("Y.bmp",ios::binary);
Z.open("Z.bmp",ios::binary);
for(i=0;i<54;i++){
c=Y.get();
c=X.get();
Z.put(c);
}
}
for(i=0;i<MAXY;i++){
for(j=0;j<3*MAXX;j++){
c=X.get();
imagen_x[i][j]=c;
c=Y.get();
imagen_y[i][j]=c;
imagen_z[i][j]=(unsigned char)0;
}
}
for(i=0;i<MAXY;i++){
for(j=0;j<MAXX;j++){
hx=(int)extrae(i,j,0,imagen_x);
hy=(int)extrae(i,j,0,imagen_y);
if((hx==254)&&(hy==0)){
for(k=0;k<3;k++)
imagen_z=modifica((unsigned char)254,i,j,k,imagen_z);
}
else{
for(k=0;k<3;k++)
imagen_z=modifica((unsigned char)0,i,j,k,imagen_z);
}
}
}
for(i=0;i<MAXY;i++){
for(j=0;j<3*MAXX;j++){
c=imagen_z[i][j];
Z.put(c);
}
}
X.close();
Y.close();
Z.close();
return 0;
II.Versión con ventanas.
También se dispone de una versión con ventanas para diferentes sistemas
operativos. Esta versión está escrita en Python (para información acerca de
Python, acudir a http://www.python.org/) y utiliza los programas
anteriores.
A continuación se describe la acción que realiza cada botón:
Borrar: limpia la pantalla.
Original: presenta la fotografía original en la pantalla.
Borde: calcula la imagen (o máscara) correspondiente a los bordes. Antes
hay que escribir las cantidades correspondientes al umbral y al número de
capas justo debajo de los botones con la etiqueta correspondiente y luego
oprimir los botones capas y umbral para introducir los dos parámetros.
Filtrado: filtra la imagen eliminando los conglomerados de tamaño menor
que el valor que le hayamos dado en el cuadro filtro (hay que apretar el
botón de filtro para introducir el parámetro).
Ruido: calcula la máscara correspondiente al ruido. Previamente hay que
introducir el valor del umbral abajo del botón con etiqueta p_umbral y
apretar p_umbral para introducir el dato.
Máscara: encuentra la máscara que especifica los pixels de la imagen
original que hay que modificar.
Final: modifica la imagen original de acuerdo a la máscara, considerando
un número de capas dado por ca_final, que hay que introducir previamente.
Total: efectúa todo el proceso completo; hay que darle los parámetros
requeridos, previamente.
Los tres siguiente siguientes botones sirven para visualizar imágenes
intermedias que resultan durante el proceso.
Salir: es para salir del programa.
A continuación se presenta el código del programa:
#Ramon Sebastian Salat Figols. Diciembre de 2007.
from Tkinter import *
import ImageTk
import Image
import os
a="c:/resultado/X.bmp"
b="c:/resultado/borde1.exe c:/resultado/X.bmp"
c="c:/resultado/filtrado2.exe c:/resultado/Y.bmp"
d="c:/resultado/ruido1.exe c:/resultado/X.bmp"
e="c:/resultado/suma1.exe c:/resultado/Y2.bmp c:/resultado/Y1.bmp"
f="c:/resultado/mascara2.exe c:/resultado/X.bmp c:/resultado/M.bmp c:/resultado/Y1.bmp"
aborde="c:/resultado/Y.bmp"
afiltrado="c:/resultado/Y1.bmp"
aruido="c:/resultado/Y2.bmp"
asuma="c:/resultado/M.bmp"
afinal="c:/resultado/R.bmp"
canx=400
cany=300
def borra():
can.delete(ALL)
def ver():
im= Image.open(a)
photoim=ImageTk.PhotoImage(im)
can.create_image(0,0,anchor=NW,image=photoim)
can.pack(expand=1,fill=BOTH,anchor=NW)
win.mainloop()
def borde():
os.system(b+" "+um+" "+ca+" 1")
im= Image.open(aborde)
photoim=ImageTk.PhotoImage(im)
can.create_image(0,0,anchor=NW,image=photoim)
can.pack(expand=1,fill=BOTH,anchor=NW)
win.mainloop()
def ca_final():
global ca_f
ca_f=e_final.get()
def umbral():
global um
um=e_umbral.get()
def capas():
global ca
ca=e_capas.get()
def filtro():
global filtro
filtro=e_filtro.get()
def p_ruido():
global pa_ruido
pa_ruido=e_ruido.get()
def filtrado():
os.system(c+" "+filtro)
im= Image.open(afiltrado)
photoim=ImageTk.PhotoImage(im)
can.create_image(0,0,anchor=NW,image=photoim)
can.pack(expand=1,fill=BOTH,anchor=NW)
win.mainloop()
def ruido():
os.system(d+" "+pa_ruido+" "+ca)
im= Image.open(aruido)
photoim=ImageTk.PhotoImage(im)
can.create_image(0,0,anchor=NW,image=photoim)
can.pack(expand=1,fill=BOTH,anchor=NW)
win.mainloop()
def suma():
os.system(e)
im= Image.open(asuma)
photoim=ImageTk.PhotoImage(im)
can.create_image(0,0,anchor=NW,image=photoim)
can.pack(expand=1,fill=BOTH,anchor=NW)
win.mainloop()
def final():
os.system(f+" "+ca_f)
im= Image.open(afinal)
photoim=ImageTk.PhotoImage(im)
can.create_image(0,0,anchor=NW,image=photoim)
can.pack(expand=1,fill=BOTH,anchor=NW)
win.mainloop()
def total():
os.system(b+" "+um+" "+ca+" 1")
os.system(c+" "+filtro)
os.system(d+" "+pa_ruido+" "+ca_f)
os.system(e)
os.system(f+" "+ca_f)
im= Image.open(afinal)
photoim=ImageTk.PhotoImage(im)
can.create_image(0,0,anchor=NW,image=photoim)
can.pack(expand=1,fill=BOTH,anchor=NW)
win.mainloop()
def v_borde():
im= Image.open(afiltrado)
photoim=ImageTk.PhotoImage(im)
can.create_image(0,0,anchor=NW,image=photoim)
can.pack(expand=1,fill=BOTH,anchor=NW)
win.mainloop()
def v_ruido():
im= Image.open(aruido)
photoim=ImageTk.PhotoImage(im)
can.create_image(0,0,anchor=NW,image=photoim)
can.pack(expand=1,fill=BOTH,anchor=NW)
win.mainloop()
def v_final():
im= Image.open(afinal)
photoim=ImageTk.PhotoImage(im)
can.create_image(0,0,anchor=NW,image=photoim)
can.pack(expand=1,fill=BOTH,anchor=NW)
win.mainloop()
def salida():
win.destroy()
win.quit()
win=Tk()
win.title('ruido01')
win.config(bg="#eee")
labelfont=('times',12,'bold')
labelfont1=('times',16,'bold')
win.minsize(width=canx+300,height=cany)
can=Canvas(win,width=canx,height=cany,bg='black',bd=5)
can.config(scrollregion=(0,0,3456,2304))
yscrollbar=Scrollbar(can,orient=VERTICAL)
xscrollbar=Scrollbar(can,orient=HORIZONTAL)
yscrollbar.config(command=can.yview)
xscrollbar.config(command=can.xview)
can.config(xscrollcommand=xscrollbar.set)
can.config(yscrollcommand=yscrollbar.set)
yscrollbar.pack(side=RIGHT,fill=Y)
xscrollbar.pack(side=BOTTOM,fill=X)
marco2=Frame(win,width=250,height=700,bg='white',bd=5)
marco2.pack(side=RIGHT)
marco1=Frame(win,width=250,height=700,bg='white',bd=5)
marco1.pack(side=RIGHT)
borrar=Button(marco1,text='borrar',command=borra,font=labelfont,width=7)
borrar.config(bg='blue',fg='white',bd=5)
borrar.pack(side=TOP)
nada=Button(marco1,width=7,font=labelfont)
nada.config(bg='#777',bd=5)
nada.pack(side=TOP)
nada1=Button(marco1,width=7,font=labelfont)
nada1.config(bg='#777',bd=5)
nada1.pack(side=TOP)
ve=Button(marco1,text='original',command=ver,font=labelfont,width=7)
ve.config(bg='blue',fg='white',bd=5)
ve.pack(side=TOP)
borde=Button(marco1,text='borde',command=borde,font=labelfont,width=7)
borde.config(bg='blue',fg='white',bd=5)
borde.pack(side=TOP)
umbral=Button(marco1, text='umbral:', command=umbral,bd=2)
umbral.config(bg='#009',fg='white',width=7,bd=5)
umbral.config(font=labelfont)
umbral.pack(side=TOP)
e_umbral=Entry(marco1,font=labelfont1,width=7,bd=5,bg='#bbb')
e_umbral.pack(side=TOP)
capas=Button(marco1, text='capas:', command=capas,bd=5)
capas.config(bg='#009',fg='white',width=7)
capas.config(font=labelfont)
capas.pack(side=TOP)
e_capas=Entry(marco1,font=labelfont1,width=7,bd=5,bg='#bbb')
e_capas.pack(side=TOP)
filtrado=Button(marco1,text='filtrado',command=filtrado,font=labelfont,width=7)
filtrado.config(bg='blue',fg='white',bd=5)
filtrado.pack(side=TOP)
filtro=Button(marco1, text='filtro:', command=filtro,bd=2)
filtro.config(bg='#009',fg='white',width=7,bd=5)
filtro.config(font=labelfont)
filtro.pack(side=TOP)
e_filtro=Entry(marco1,font=labelfont1,width=7,bd=5,bg='#bbb')
e_filtro.pack(side=TOP)
qruido=Button(marco2,text='ruido',command=ruido,font=labelfont,width=7)
qruido.config(bg='blue',fg='white',bd=5)
qruido.pack(side=TOP)
pa_ruido=Button(marco2, text='p_ruido:', command=p_ruido,bd=5)
pa_ruido.config(bg='#009',fg='white',width=7,bd=5)
pa_ruido.config(font=labelfont)
pa_ruido.pack(side=TOP)
e_ruido=Entry(marco2,font=labelfont1,width=7,bd=5,bg='#bbb')
e_ruido.pack(side=TOP)
suma=Button(marco2,text='mascara',command=suma,font=labelfont,width=7)
suma.config(bg='blue',fg='white',bd=5)
suma.pack(side=TOP)
resultado=Button(marco2,text='final',command=final,font=labelfont,width=7)
resultado.config(bg='blue',fg='white',bd=5)
resultado.pack(side=TOP)
l_todo=Button(marco2, text='ca_f:', command=ca_final,bd=2)
l_todo.config(bg='#009',fg='white',width=7,bd=5)
l_todo.config(font=labelfont)
l_todo.pack(side=TOP)
e_final=Entry(marco2,font=labelfont1,width=7,bd=5,bg='#bbb')
e_final.pack(side=TOP)
todo=Button(marco2,text='total',command=total,font=labelfont,width=7)
todo.config(bg='blue',fg='white',bd=5)
todo.pack(side=TOP)
vborde=Button(marco2,text='ver borde',command=v_borde,font=labelfont,width=7)
vborde.config(bg='#777',fg='white',bd=5)
vborde.pack(side=TOP)
vruido=Button(marco2,text='ver ruido',command=v_ruido,font=labelfont,width=7)
vruido.config(bg='#777',fg='white',bd=5)
vruido.pack(side=TOP)
vtodo=Button(marco2,text='ver final',command=v_final,font=labelfont,width=7)
vtodo.config(bg='#777',fg='white',bd=5)
vtodo.pack(side=TOP)
salir=Button(marco2,text='salir',command=salida,font=labelfont,width=7)
salir.config(bg='#777',fg='white',bd=5)
salir.pack(side=TOP)
can.pack(expand=1,fill=BOTH)
win.mainloop()
Descargar