81
Casa Abierta al Tiempo Universidad Autónoma Metropolitana Unidad Iztapalapa División de Ciencias Básicas e Ingeniería Departamento de Ingeniería Eléctrica Licenciatura en Computación Reporte del proyecto terminal: Reconocimiento Óptico de Caracteres a través de Redes Neuronales Ricardo Díaz Santiago y!? ;{:i ,:: 5,+~ Director de proyecto: Dr. John Goddard Close

Casa Abierta Tiempo Universidad Autónoma …148.206.53.84/tesiuami/UAM1968.pdf · Reconocimiento Óptico de Caracteres a través de Redes Neuronales Ricardo Díaz Santiago y!? ;{:i

Embed Size (px)

Citation preview

Casa Abierta al Tiempo

Universidad Autónoma Metropolitana Unidad Iztapalapa

División de Ciencias Básicas e Ingeniería Departamento de Ingeniería Eléctrica

Licenciatura en Computación

Reporte del proyecto terminal: Reconocimiento Óptico de Caracteres

a través de Redes Neuronales

Ricardo Díaz Santiago y!? ;{:i ,:: 5,+~ Director de proyecto: Dr. John Goddard Close

Índice General

1 Redes Neuronales 5 1.1 Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.2 Redes Neuronales Biológica . . . . . . . . . . . . . . . . . . . 6 1.3 Redes Neuronales Artificiales . . . . . . . . . . . . . . . . . . . 7 1.4 La utilidad de las redes neuronales . . . . . . . . . . . . . . . 11

2 Retropropagación 15 2.1 Operación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 2.2 La Regla Delta Generalizada . . . . . . . . . . . . . . . . . . . 17

2.2.1 Actualización de los pesos de la capa de salida . . . . . 20 2.2.2 Actualización de los pesos de la capa escondida . . . . 23

3 Implantación 27

4 Conclusiones 39

A Extraccción de Regiones 43 A.l Definiciones para el manejo de archivos gráficos . . . . . . . . 43 A.2 Definiciones para la extracción de zonas . . . . . . . . . . . . . 50 A.3 Funciones para la segmentación de regiones . . . . . . . . . . . 52 A.4 Funciones de escalamiento y miscelánea . . . . . . . . . . . . 72

... 111

Índice de Figuras

1.1 Una neurona consiste de un cuerpo celular. un axón. y muchas dendritas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

1.2 Una neurona simulada . . . . . . . . . . . . . . . . . . . . . . 8 1.3 Estructura de una Red Neuronal . . . . . . . . . . . . . . . . 11 1.4 Una red neuronal que reconoce familiares y conocidos . Todos

los pesos excepto los indicados son 1.0 Los valores de umbral se indican dentro de los nodos . . . . . . . . . . . . . . . . . . 12

2.1 Arquitectura de una red de retropropagación . . . . . . . . . . 18 2.2 La función Sigmoide . . . . . . . . . . . . . . . . . . . . . . . . 22

4.1 Función de error durante el entrenamiento de !la red . . . . . . . 39

1

Introducción

La aparición tanto de las computadoras digitales y el desarrollo de teorías modernas del aprendizaje y procesamiento neuronal ocurrieron aproxima- damente al mismo tiempo a finales de los años 40. Desafortunadamente el estudio de los Sistemas Neuronales Artzjciales (o ANS por sus siglas en inglés) no siempre tuvo aceptación en los campos de ingeniería debido a los problemas que presentó uno de los primeros modelos: el perceptrón.

Sin embargo a partir de los años 80 la popularidad de l a s redes neurona- les ha crecido rápidamente. Estas redes parecen ser ca:paces de resolver de manera relativamente fácil algunos problemas que en otro caso son difíciles de resolver con algoritmos convencionales. Especialmente las tareas de reco- nocimiento de patrones se llevan a cabo muy bien por algunas redes.

Este reporte muestra los resultados obtenidos en el proyecto terminal de reconocimiento óptico de caracteres utilizando una red n.eurona1 de retropro- pagación (BPN por sus siglas en inglés).

3

Capítulo 1

Redes Neuronales

l. 1 Introducción La base de estudio de las redes neuronales es tratar de irnodelar la forma en que trabaja el cerebro humano.

Hay muchas descripciones posibles de una red neuronal biológica. Algu- nas de las posibles descripciones son:

o morfológicas

o químicas (la descripción de las reacciones química6 y materiales invo- lucrados, por ejemplo neurotransmisores)

o biológicas (descripción de las neuronas como células biológicas)

o físicas (descripción de un sistema de grandes congregados de neuronas)

0 psicológicas (descripción de comportamientos)

El ítern perdido en esta lista es una descripción del tipo de cálculos eje- cutados y llevados a cabo y los algoritmos usados por una red neuronal. La naturaleza de esos cálculos aún no se conoce con precisión.

Una de las formas de explorar los modelos computacionales usados por el cerebro es hacer un estudio de las redes neuronales artificiales. Tales redes

5

6 l. Redes Neuronales

son modelos inspirados por el cerebro. Usualmente se comienza con modelos muy simples que llevan a cabo únicamente unas cuantas tareas, otras carac- terísticas que incrementan la complejidad se introducen poco a poco cuando el modelo actual no puede llevar a cabo la siguiente tarea. Se han propuesto más de 50 redes en la literatura.

1.2 Redes Neuronales Biológicas La mayoría de las neuronas, como la que se muestra en la figura 1.1 consisten de un cuerpo celular mas un azón y muchas dendritas. El axón es una pro- tuberancia que conecta la salida de una neurona con otras otras neuronas. Las dendritas son protuberancias que proveen conexión de las neuronas con otras neuronas.

k Cuerpo Celular

suficente área para facilitar la

\ .

Figura 1.1: Una neurona consiste de un cuerpo celular, un axón, y muchas dendrit as

Una neurona no hace nada a menos que la influencia colectiva de todas sus entradas alcance un cierto nivel de umbral. Siempre que ése nivel sea

1.3. Redes Neuronales Artificiales 7

alcanzado, la neurona produce una salida en forma de un pulso estrecho pro- cedente del cuerpo celular, a través del axón, y dentro de las ramificaciones del axón, en este caso decimos que la neurona se dispara. Dado que una neu- rona tiene este comportamiento, decimos que es un dispositivo de todo o nada.

Los axones tienen influencia sobre las dendritas so'bre intervalos estre- chos llamados synapsis. La estimulación en algunas sinapsis estimulan a las neuronas a dispararse, y en otras se estimula justamente lo contrario. Hay evidencia que el aprendizaje se lleva a cabo en la vecindad de sinapsis y que tiene que ver con el grado al cual las sinapsis traducein el pulso que viaja a través del axón de una neurona en una excitación o inhibición hacia la siguiente neurona.

El cerebro humano consiste de un gran número de neuronas (estimado entre 1 O 1 O y 1013). Si éste número es exorbitante, el número de sinapsis lo es aún más. En el cerebelo - la parte del cerebro crucial ]para la coordinación

' motriz - cada neurona puede recibir entradas del orden de lo5 sinapsis.

Hay evidencia morfológica que el número de sinapsis en el cerebro se in- crementa rápidamente con la edad. Se cree que éste es uno de los mecanismos que le permiten aprender al cerebro.

1.3 Redes Neuronales Artificiales

Las redes neuronales simuladas, consisten típicamente de neuronas simuladas como la que se muestra en la figura 1.2. La neurona simulada se puede ver como un nodo conectado a otros nodos a través de ligas que corresponden a las conexiones axón-sinapsis-dendritas.

Cada liga está asociada con un peso. Como una sin,apsis, ese peso deter- mina la naturaleza y la intensidad de la influencia de un nodo en otro. Más especificamente, la influencia de un nodo en otro es el producto del valor de salida de la neurona multiplicado por el peso asignado a la liga. Por lo tanto, un número grande positivo corresponde a una excitación alta, y un valor pequeño negativo corresponde a una inhibición débil.

8 l. Redes Neuronales

W

t

Figura 1.2: Una neurona simulada

Así, cada nodo combina las influencias separadas recibidas en sus ligas de entrada, en una influencia total usando una función de activación. Una función de activación simple pasa la suma de los valores de entrada a través de una función umbral para determinar la salida del nodo. La salida de cada nodo es o bien O o bien 1 dependiendo si la suma de las entradas está por de- bajo por encima del valor de umbral usado por la función de umbral del nodo.

De aquí se puede ver que los pesos modelan propiedades sinápticas; el sumador modela la capacidad de combinar influencias de l a s dendritas; y fi- nalmente la comparación con un umbral modela la característica todo o nada impuesta por por los mecanismos electroqímicos en el cuerpo celular.

Por otro lado, mucho del carácter de las neuronas reales no se modela. Una neurona simulada simplemente suma pesos ponderados de sus entradas.

1.3. Redes Neuronales Artificiales 9

Las neuronas reales pueden procesar información vía complicados mecanis- mos dendríticos que traen a la mente líneas de transmisión electrónica y circuitos lógicos. Una neurona simulada permanece encendida en tanto la suma de sus pesos de entrada esté por arriba de un valor de umbral. Las neuronas reales pueden codificar mensajes a través de complicados arreglos de pulsos reminiscentes de la modulación en frecuencia y el multiplexaje.

De acuerdo a ello, los investigadores discuten si las redes neuronales si- muladas dan idea de la actividad neuronal y si esas redes pueden ejecutar cualquier cosa de forma tan maravillosa como las reales. Mucha gente consi- dera a las redes neuronales reales tan diferentes de l a s simulaciones contem- poráneas, que siempre se toman el cuidado de usar los calificativos simulada o real, siempre que utilizan la frase red neuronal.

En lo que resta del texto, sin embargo, omitiremos la palabra simulada para evitar la tediosa repetición.

Para nosotros, una red neuronal es una estructura de procesamiento de in- formación distribuida, en forma de un grafo, con las siguientes sub-definiones y restricciones:

1. Los nodos del grafo se les llama elementos de procesamiento.

2. Las ligas del grafo se les conoce como conexiones. Cada conexión funciona como una ruta unidireccional instanánea de conducción de señales.

3. Cada elemento de procesamiento puede recibir cualquier número de conexiones entrantes (también llamadas conexiones de entrada).

4. Cada elemento de procesamiento puede tener cualquier número de de conexiones salientes, pero las señales en todas ellas deben ser las mis- mas. En efecto, cada elemento de procesamiento tiene una única co- nexión de salida que se puede ramificar (o tener un fan out) en copias para formar múltiples conexiones (a veces llamadas colaterales), cada una de las cuales lleva la misma señal idéntica (la señal de salida del elemento procesador).

5. Los elementos de procesamiento pueden tener memoria local.

10 l. Redes Neuronales

6. Cada elemento de procesamiento posee una función de transferencia la cual puede usar (y alterar) la memoria local, puede usar las señales de entrada, y es esta función en última instancia la que produce la señal de salida del elemento de procesamiento. En otras palabras, l a s únicas entradas permitidas a la función de transferencia son los valores almacenados en la memoria local del elemento de procesamiento y los valores actuales de las señales de entrada en las conexiones recibidas por el elemento de procesamiento. Las únicas salidas permitidas por la función de transferencia son valores a ser almacenados en la memoria local del elemento de procesamiento y la señal de salida del elemento de procesamiento. Las funciones de transferencia pueden operar continua- mente o episódicamente. En éste último caso debe haber una entrada lamada activación la cual provoca que la función de transferencia del elemento de procesamiento opere en las señales actuales de entrada y los valores de la memoria local produciendo una señal de salida actua- lizada (y posiblemente modificando los valores de la memoria local). Los elementos de procesamiento continuos siempre están operando. La entrada de activación llega a través de una conexión de un elemento de procesamiento planificador, el cual es parte de la red.

7. La señales de entrada de una red neuronal fuera de la misma red llegan vía conexiones originadas en el mundo exterior. Las salidas de la red son conexiones que dejan la red.

Definamos la estructura de una Red Neuronal como una colección de procesadores paralelos conectados en forma de un grafo dirigido. Podemos representar esquemáticamente cada elemento de procesamiento (o unidad) en la red como un nodo con las conexiones entre las unidades indicadas por por los arws como en la figura 1.3. Indicamos la dirección del flujo de la información a través del uso de flechas en las conexiones.

Viendo la figura 1.3 notamos 3 vectores de nodos (capas) a saber:

o La capa de entrada

o La capa intermedia o capa escondida

o La capa de salida

1.4. La utilidad de las redes neuronales 11

c u p u O c u l t u

E n t r u d u s

Figura 1.3: Estructura de una Red Neuronal

1.4 La utilidad de las redes neuronales

Las redes neuronales pueden reconocer regularidad en los datos de entrada. Para darnos una idea de cómo es que esto ocurre, consilderemos la red neu- ronal que se muestra en la figura 1.4.

La red está equipada con pesos que la hacen capaz de reconocer propie dades de pares de personas. Algunos pares involucran familiares y otros, personas conocidas.

Dos conexiones de entrada reciben un valor de 1 para identificar el par de personas bajo consideración. Todas l a s otras conexiones de entrada reciben el valor de O porque l a s personas correspondientes no no forman parte del par

12 1. Redes Neuronales

HI

Felipe - Julieta / Fernanda -,, H2

.iares

Figura 1.4: Una red neuronal que reconoce familiares y conocidos. Todos los pesos excepto los indicados son 1.0 Los valores de umbral se indican dentro de los nodos

en consideración. Podemos además suponer que las personas en el primer grupo de tres son familiares, y de igual forma el otro grupo. Otra considera- ción en este caso es que cualquier par de personas que no son familiares son conocidos.

Los nodos justo a la derecha de l a s ligas de entrada (las etiquetadas con H1 y H2) corresponden a los nodos escondidos o capa escondida, porque sus salidas no son observables. Los nodos de salida conllevan las conclusiones. El nodo Conocidos, por ejemplo recibe el valor de 1 cuando el arreglo de entradas corresponde a dos personas que son conocidos.

Cualquiera de las tres primeras entradas produce suficiente estimulación para encender H1, porque todos los pesos conectados son 1.0 y porque el umbral de H1 es 0.5. De forma similar cualquiera de las tres entradas del segundo grupo puede encender H2. Por lo tanto H1 y H2 actúan como com- puertas lógicas OR. Al menos una de H I y H2 se tienen que encender, dada la presuposición que siempre se encienden dos entradas.

1.4. La utilidad de las redes neuronales 13

Si tanto H1 y H2 se encienden, entonces la suma ponderada que se presen- t a al nodo Conocidos es 2 porque ambos pesos involucntdos son 1 y porque el umbral del nodo es 1.5. Si sólo uno de los dos (H1 y H2) se enciende en- tonces el nodo Conocidos no se encenderá. De aquí podemos decir que &te nodo actúa como una compuerta lógica AND: sólo enciende cuando el par de entradas son conocidos.

Por otro lado, si tanto H1 y H2 se encienden, la suma ponderada que se presenta al nodo Familiares es -2 dado a los pesos inhibitorios -1. El valor -2 es menor al valor de umbral del nodo que es de -1.5, así que el nodo no enciende. Si solamente uno de los dos nodos H1 y H2 encienden, entonces la suma ponderada es -1, la cual está por arriba del valor de umbral del nodo Familiares de -1.5 y por lo tanto enciende. De esta forma el nodo enciende si y sólo si el par de entradas son familiares.

Es de notar que cada liga y cada nodo en éste ejemplo tienen un rol claro. Generalmente, sin embargo, la capacidad de reconocimiento se distribuye de forma difusa sobre muchos nodos y pesos, como podrem'os ver de forma sub- secuente. De acuerdo a ello, el rol de ligas particulares y nodos escondidos se vuelve oscuro.

14 l. Redes Neuronales

Capítulo 2

Retropropagación

Hay procedimientos sorprendentemente simples que les ]permiten a los pesos de las redes neuronales aprender a partir de entrenar ejemplos.

El procedimiento de la red de Retropropagación (BPN) es una forma rela- tivamente eficiente de calcular qué tanto se mejora el rendimiento a partir de cambios a pesos individualmente. El procedimiento se llama retropropaga- ción porque como pronto se verá, primero calcula los cambios en la capa final, reutliza mucho de tal computación para calcular los cambios en la penúltima capa y finalmente retrocede a la capa inicial.

2.1 Operación

Para empezar, la red aprende un conjunto predefinido de pares entrada- salida, usando un ciclo de dos fases propagación-adaptación. Después de que un patrón de entrada se ha aplicado como un estímulo it la primera capa de la red, se propaga hacia cada capa superior hasta que se genera una salida. Este patrón de salida se compara con la salida deseada y una señal de error se calcula para cada unidad de la capa de salida.

Las señales de error se transmiten entonces hacia atrás, de la capa de sa- lida a cada nodo de la capa intermedia (escondida) que contribuya de forma directa con la salida. Sin embargo cada unidad en la c?pa intermedia recibe sólo una porción de la señal total de error, basada aproximadamente en la contribución relativa que la unidad proporciona a la salida original. Este

15

16 2. Retropropagación

proceso se repite, capa por capa, hasta que cada nodo en la red ha recibido una señal de error que describe su contribución al error total. Basados en las señales de error recibidas, los pesos de las conexiones se actualizan por cada unidad para provocar que la red tienda a converger hacia un estado que permita que todos los patrones se codifiquen.

La significancia de éste proceso es que, conforme la red se entrena, los nodos en la capa intermedia se organizan a si mismos de forma tal que dife- rentes nodos aprenden a reconocer diferentes características del espacio total de entrada. Después del entrenamiento, cuando se le presente un patrón arbitrario que sea ruidoso o incompleto, las unidades en la capa intermedia de la red responderán con una salida activa si la nueva entrada contiene un patrón que se parece a las unidades individuales que se aprendieron a re- conocer durante el entrenamiento. De forma contraria, las unidades de la capa intermedia tienen una tendencia de inhibir sus entradas si el patrón de entrada no contiene la característica que fueron entrenados para reconocer.

Conforme las señales se propagan a través de las diferentes capas en la red, el patrón de actividad que se presenta en cada capa se puede pensar como un patrón con características que se pueden reconocer por unidades en la capa subsecuente. El patrón de salida generado se puede pensar co- mo un mapa de características que provee una indicación de la presencia o ausencia de muchas diferentes combinaciones de características en la entrada.

El efecto total de este comportamiento es que la BPN provee un medio efectivo de permitirle a un sistema de cómputo examinar patrones de datos que pueden ser incompletos, o ruidosos, y reconocer patrones sutiles a partir de entradas parciales.

Varios investigadores han mostrado que durante el entrenamiento, BPN tiende a desarrollar relaciones internas entre los nodos y así organizar los da- tos en clases de patrones. Esta tendencia puede ser extrapolada a la hipótesis de que todas las unidades de la capa escondida en la BPN están de alguna forma asociadas con características específicas del patrón de entrada como un resultado del entrenamiento. Exactamente lo que la asociación es puede o no ser evidente al ojo humano. Lo que es importante es que la red ha encontrado una representación interna que la habilita para generar las sa- lidas deseadas, cuando se dan las entradas de entrenamiento. Esta misma

2.2. La Regla Delta Generalizada 17

representación interna se puede aplicar a entradas que 130 fueron usadas en el entrenamiento. La BPN clasificará esas entradas que no han sido vistas previamente de acuerdo a las características que comparten con los ejemplos de entrenamiento.

2.2 La Regla Delta Generalizada.

En esta sección, presentamos la descripción matemática formal de la ope- ración de BPN. Presentaremos una derivación detallada de la regla delta generalizada (GDR), la cual es el algoritmo de aprendizaje de la red.

La figura 2.1 sirve como referencia en la mayor paate de la discusión. BPN es una red con alimentación hacia adelante en capas las cuales están completamente interconectadas. Por lo tanto, no hay co:nexiones de retroali- mentación así como tampoco ninguna conexión que traspase una capa para ir directamente a una capa posterior. Aunque en esta discusión sólo se utilizan tres capas, en teoría se permiten más de una capa escondida.

Una red neuronal se llama red de mapeo si es capaz de calcular alguna relación funcional entre su entrada y su salida. Por ejemplo, si la entrada de una red es el valor de un ángulo y la salida es el coseno de tal ángulo, la red ejecuta el mapeo 8 + cos(8). Para una función tan simple no necesitamos una red neuronal; sin embargo, podríamos querer ejecutar un mapeo com- plicado donde no sabemos cómo describir la relación funcional de antemano, pero para la cual conocemos ejemplos del mapeo correcto.

En esta situación, el poder de una red neuronal para descubrir sus propios algoritmos es extremadamente útil.

Supongamos que tenemos un conjunto P de pares de vectores, (zl, yl), (z2, y2), ...,( zp, yp) los cuales son ejemplos de un mapeo funcional y = z E RN, y E RM. Queremos entrenar a la red de tal forma que aprenda una aproximación o = y' = $'(x). Derivaremos un método para hacer este entre- namiento, que usualmente funciona, presuponiendo que los pares de vectores de entrenamiento hayan sido escogidos de forma apropiada y haya un número suficiente de ellos. (Las definiciones de propiamente y suficiente) se darán

18 2. Retropropagación

Figura 2.1: Arquitectura de una red de retropropagación

posteriormente. Recordemos que el aprendizaje en una red neuronal signifi- ca encontrar un conjunto apropiado de pesos. La técnica de aprendizaje que describimos aquí se parece al probIema de encontrar la ecuación de una línea que mejor ajusta una cantidad de puntos conocidos. Para un problema de ajuste de rectas probablemente utilizaríamos una aproximación de mínimos cuadrados. Dado que la relación que estamos tratando de mapear es más bien no lineal, utilizamos una versión iterativa del mktodo de mínimos cua- drados, llamada técnica del descenso más rápido.

Para comenzar, revisemos las ecuaciones para el procesamiento de in- formación en la red de 3 capas de la figura 2.1. Un vector de entrada, xp = (zpl, xp2, ..., Z ~ N ) ~ , se aplica a la capa de entrada de la red. Las unida-

2.2. La Regla Delta Generalizada 19

des de entrada distribuyen los valores a las unidades de la capa escondida. La entrada a la j-ésima unidad escondida es

N net:j = wj”ixpi + “3

i=l

donde w$ es el peso de la conexión de la i-ésima unidad de entrada, y 0; es el término de polarización. El superíndice ‘3” se refiere a cantidades en la capa escondida. Suponiendo que la activación de éste nodo es igual a la entrada de la red; entonces, la salida de este nodo es

Las ecuaciones para los nodos de salida son

El conjunto inicial de valores de los pesos representa una primera a p r e ximación a los valores correctos para los pesos del problema. A diferencia de otros métodos la técnica que empleamos aquí no depende de hacer una buena primera aproximación. El procedimiento básico para entrenar la red está englobado en la siguiente descripción:

1. Aplicar un vector de entrada a la red y calcular los correspondientes valores de salida.

2. Comparar los valores actuales de salida con los valores de salida correc- tos y determinar una medida del error.

3. Determinar en qué dirección (+ o -) cambiar cada peso para reducir el error.

4. Determinar la cantidad en la cual cambiar cada peso.

5. Aplicar l a s correciones a los pesos.

20 2. Retropropagación

6. Repetir los pasos 1 a 5 con todos los vectores de entrenamiento hasta que que el error para todos los vectores en el conjunto de entrenamiento se reduzca a un valor aceptable.

Una ley iterativa para el cambio de pesos de una red sin capas escondidas y con unidades de salida lineales es la regla delta:

w(t + l)z = W ( t > i + 2jE’lCXki

donde 1.1 es una constante positiva, ~ k i es la i-ésima componente del k- ésimo vector de entrenamiento, y &k es la diferencia entre la salida actual y el valor correcto, &k = ( d k - yk).

Una ecuación similar resulta cuando la red tiene más de 2 capas, o cuan- do las funciones de salida no son lineales. A continuación derivaremos los resultados de forma explícita.

2.2.1 Actualización de los pesos de la capa de salida

Dado que hay múltiples unidades en una capa, un sólo valor de error como ~ k , no es suficiente para BPN. Definiremos el error en una sola unidad de salida como b,pk = (ypk - opk), donde el subíndice (‘p” se refiere al pésimo vector de entrenamiento y “k” se refiere a la k-ésima unidad de salida. En este caso, y,k es el valor de salida deseado, y opk es el valor actual de salida de la k-ésima unidad. El error que se minimiza por la GDR es la suma de los cuadrados de los errores para todas las unidades de salida:

El factor en la ecuación 2.6 es por conveniencia al calcular derivadas posteriormente. Puesto que una constante arbitraria aparecerá en el resulta- do final, la presencia de este factor no invalida la derivación.

Para determinar la dirección en la cual cambiar los pesos, calculamos el negativo del gradiente de E,, VE,, con respecto a los pesos, w k j . Entonces, podemos ajustar los valores de los pesos de forma tal que el error total se

2.2. La Regla Delta Generalizada 21

reduce. Frecuentemente es útil pensar en E, como u.na superficie en un espacio de pesos.

Para mantener las cosas simples, consideraremos cada componente VE, separadamente. De la ecuación 2.6 y la definición de 6pk

Y

donde hemos usado la ecuación 2.4 para el valor de salida. opk, y la regla de la cadena para derivadas parciales. Por el momento, no trataremos de evaluar la derivada de fi, en lugar de ello, la escribiremos simplemente como fko)(netik). El último factor de la ecuación 2.8 es

Combinando las ecuaciones 2.8 y 2.9, tenemos para el negativo del gra- dient e

En cuanto a la magnitud del cambio de pesos se refiere, lo tomamos como proporcional al negativo del gradiente. Por lo tanto, los pesos en la capa de salida se actualizan de acuerdo a

wgj(t + 1) = wij(t) + Apwij(t) (2.11)

donde Apwij = v(YP/P~ - ~ p k ) j i (net;k)ipj (2.12)

El factor 7 se llama parúmetro de tasa de aprendizaje, por el momento es suficiente saber que es positivo y usualmente menor a 1.

Regresemos a la función ft . Primero, hay que notax el requerimiento de que la función sea diferenciable. Tal requerimiento elimina la posibilidad de usar una unidad con umbral lineal como la que hemos visto previamente, puesto que la función de salida de dicha unidad no es diferenciable en el

22 2. Retropmpagacidn

punto de umbral. Hay dos formas de la función de salida que son interesantes:

0 f[(netjok) = net;,

o f[(neto = (1 + e-net;k 1-1 Jk

La primera función define la unidad de salida lineal. A La última función se le llama función sigmoide o logística; se ilustra en la figura 2.2.

La elección de la función de salida depende en cómo se escogió repre- sentar los datos de salida. Por ejemplo, si se quiere que los datos de salida sean binarios, usaremos una función de salida sigmoide, puesto que limita la salida y es casi biestable, pero también es diferenciable. En otros casos, una función lineal o una sigmoide es apropiada.

1

0.9

0.8

0.7

0.6

0.5

0.4

0.3

0.2

0.1

O -4 -2 O 2 4

Figura 2.2: La función Sigmoide.

En el primer caso, ff = 1; en el segundo caso f f = f{( 1 - f[) = Opk (1 - o p k ) . En ambas situaciones, tenemos:

(2.13)

2.2. La Regla Delta Generalizada 23

para la salida lineal y

(2.14)

para la salida sigmoidal.

siguiente cantidad Podemos resu.mir las ecuaciones de actualización de pesos, definiendo la

Con lo que podemos reescribir la ecuación de actualización como:

(2.15)

(2.16)

Sin importar la forma funcional de la función de salida &’. Queremos hacer un comentario con vistas a la relación entre el método

del gradiente descendiente descrito aquí y la técnica de lmínimos cuadrados. Si estuviéramos tratando de hacer la regla delta generalizada completamente análoga a un método de mínimos cuadrado, no cambiaríamos ninguno de los valores de los pesos hasta que todos los patrones de entrenamiento hubiesen sido presentados a la red una vez. Simplemente acumularíamos los cambios conforme cada patrón se procese,los sumaría mos y realizaríamos una actua- lización a los pesos. Entonces repetiríamos el proceso hesta que el error sea aceptablemente bajo. El error que minimiza este proceso es

P E = ~ E , (2.17)

p= 1

donde P es el número de patrones en el conjunto de entrenamiento. En la práctica se ha visto que hay poca ventaja a esta adherencia estricta con el método de mínimos cuadrados. De hecho, se debe almacenar una gran cantidad de información para usar este método.

2.2.2 Actualización de los pesos de la capa escondida Nos gustaría repetir para la capa escondida, los mismos cAlculos que llevamos a cabo para la capa de salida, sin embargo surge un problema cuando trata- mos de de determinar una medida del error de la salida d.e las unidades de la capa escondida: Sabemos que cuál es el valor actual de la, salida, pero no hay

24 2. Retropropagación

forma de saber por adelantado, cuál debe ser el valor de salida correcto para para tales unidades . Intuitivamente, el error total, Ep debe estar relacionado de alguna manera con los valores de salida de la capa escondida. Podemos verificarlo a través de la ecuación 2.7

Sabemos por l a s ecuaciones 2.1 y 2.2, que ipj depende de los pesos de la capa escondida . Podemos utilizar este hecho para calcular el gradiente de Ep con respecto a los pesos de la capa escondida.

Cada uno de los factores de la la ecuación 2.18se pueden calcular a partir de ecuaciones previas, el resultado es

(2.19)

Actualizamos los pesos de la capa escondida proporcionalmente al negativo de la ecuación 2.19

donde otra vez q es la tasa de aprendizaje. Podemos usar la definición de b:k dada anteriormente para escribir

(2.21)

2.2. La Regla Delta Generalizada 25

Hay que notar que cada actualización de pesos de la capa oculta depende de todos los términos de error, en la cap ade salida. En este resultado es donde surge la noción de Retropropugacio'n. Los errores que se conocen en la capa de salida son propagados hacia atrds hacia la capa oculta para deter- minar el cambio apropiado de los pesos en la capa. Definiendo un término de error de la capa escondida

k

hacemos que las ecuaciones de actualización de procesos se vuelvan análogas a l a s correspondientes a la capa de salida:

(2.23)

26 2. Retropropagacidn

Capítulo 3

Implantación

Una vez explicado qué es y cómo funciona una red neuronal de Retropropaga- ción en este capítulo explicaremos la forma en que implantamos un simulador para BPN. a través del código en C de su implantación.

#include <stdio . h> #include <math. h> #include <string. h> #include <stdlib. h> #include <coni0 . h> #include <ctype . h>

#define InputUnitNo 63 // dimension de la capa de entrada #define HiddenUnitNo 30 // dimension de la capa escondida #define OutputUnitNo 10 // dimension de la capa de salida #define MaxPatternNo 20 // valor maxim0 de patrones de aprendizaje

typedef struct parms parms; struct parms {

int InUnitNo, HiUnitNo, OutUnitNo, MaxPatNo, learningpatternno,

27

28 3. Implantación

iter; float Eta, // Eficiencia del aprendizaje

Alpha, // Constante del ponderamiento anterior Errorhnc, // Error al final del aprendizaje Wmin, // Valor minimo de la ponderacion inicial Wmax; // Valor rnaximo de la ponderacion inicial

}BPNPar;

float ol[MaxPatternNo][InputUnitNo]; // valor de salida de la unidad de

float 02[HiddenUnitNo]; // valor de salida de la unidad escondida float 03[0utputUnitNo]; // valor de salida de la unidad de salida float t[MaxPatternNo][OutputUnitNo]; // sena1 de patron maestra float w2l[HiddenUnitNo][InputUnitNo]; // Pesos

float dw21[HiddenUnitNo][InputUnitNo]; float w32[0utputUnitNo][HiddenUnitNo]; // pesos

float dw32[0utputUnitNo] [HiddenUnitNo]; float bias2[HiddenUnitNo]; // valor de la unidad escondida float dbias2[HiddenUnitNo]; float bias3[OutputUnitNo]; // valor de la unidad de salida float dbias3[OutputUnitNo];

entrada

u-entrada->u-escondida

u-escondida->usalida

int test-patternno; // numero de patrones revisados despues // del aprendizaje

void propagation(int p); void back-propagation(int p); void state(int); void readfile(char *); void initialize(void); void asincrona( int); void eliminarebote(v0id); inline float rnd()

29

{ return ((float)rand()/Ox’lFFF *

inline float f(float x) // Esta es la funcion Sigmoide (BPNPar.Wmax-BPNPar.Wmin)+BPNPar.Wmin); };

{ return( I/( l+exp(-(x) ) ) 1; 1;

void main (void) {

int i ,j ,k; char filename[30]; char ss[80]; float errorfunc; FILE *rp;

// contadores de ciclos // archivo de datos // string de trabajo

// variable cont/error // File p. p/estadisticas.

if( (rp =fopen( ‘ ‘ StatBpn’ ’ , ‘ ‘ at ’ ’))==NULL) {

fprintf(stderr,‘ ‘Error al abrir archivo de

exit(-1); estadisticas. . . ! ! \n’ ’);

clrscr();

printf( ‘ ‘Archivo de Aprendizaje : ’); gets(ss); sscanf(ss, ‘ ‘%S ’ ’ ,filename);

printf( ‘ ‘Numero Aleatorio : ”); gets(ss); srand( atoi(ss) ) ; read file( filename) ; // leer archivo de datos if(BPNPar.iter == O)

{ initialize(); // inicialixacion de pesos printf(‘ ‘ Antes del Aprendizaje \n’ ’);

1 else

printf( “ Resultados de la ultima iteracioln \n’ ’);

30 3. Implantación

printf( ‘ ‘ \tPatron \n ’ ’ );

for(errorfunc = 0.0, i = O; i <BPNPar.learning-patternno; i++) {

state (i); for (j = 0; j <OutputUnitNo; j++ )

1 errorfunc += pow( t [i]lj]-o3Ij], 2.0);

errorfunc /= 2; i = BPNPar.iter; printf ( ‘ ‘errorfunc : %3f\n’ ’ ,errorfunc); if( BPNPar.iter == O )

printf( ‘ ‘ \n Aprendiendo. . . \n ’ ’); printf( “Cont patron sal1 sa12 sa13 sal4\n”); for( i = BPNPar.iter; errorfunc > BPNPar.ErrorF’unc;)

for( j = O ; j < BPNPar.learning-patternno; j++)

fprintf(rp,‘ ‘O ,%f\n’ ’,errorfunc);

{

{ propagation(j); back-propagation(j);

1

{ for( errorfunc =0.0, j=0; j <BPNPar.learning-patternno; j++)

printf( ‘%4d ’ ’ ,++i); state(j); for(k = 0; k < OutputUnitNo; k++)

errorfunc += pow(t[j][k] - o3[k], 2.0); 1 errorfunc /= 2; printf(‘ ‘ Errorfunc : %3f \n’ ’, errorfunc ); fprintf(rp, ‘ ‘ %d, %f \n ’ ’ ,i,errorfunc); asincrona(i);

// Termina el aprendizaje

31

printf( ‘ \tPatron sal1 sa12 sa13 sal4\n’ ’);

// ejecuta y despliega patrones de prueba for(i=O; i <BPNPar.learning-patternno ; i++)

fclose(rp); state( i );

} // Fin del main

// Moviendo datos de la capa de entrada a la capa de salida void propagation (int p) { // P es el numero de patron de aprendizaje

int i j ; // Contadores de ciclos float net; // variable de suma de productos

// Valor de salida de una! unidad escondida.

for ( i=O; i<HiddenUnitNo;i++ ){ for( net=(), j=O; j<InputUnitNo; j++)

02[i] = f( net+bias:![i] ); net+=w2l[i]lj]*ol[p]lj];

1 // Valor de salida de una unidad de salida

for( i=O; i < OutputUnitNo; i++ ) {

net += w32 [i] b] *o2 b] ; for( net =O, j=O; j < HiddenUnitNo; j++)

03[i] =f( net + bias3[i]); }

// Fin de Propagation

// Corrigiendo los pesos

32 3. Implantación

void back-propagation (int p) // P es el numero de patron de aprendizaje

{ int i j ; // Contadores de ciclo float d2[ Hiddenunit No] ; // Valores de correccion de pesos d

// entrada-> escondida

float d3[0utputUnitNo]; // Valores de correccion de pesos d // Escondida->salida

float sum; // Variable para el calculo de la suma de productos // d j = (o j - yj)f(ij)

for ( i=O; i<OutputUnitNo; i++ ) d3[i] = ( t[p][i]-o3[i]) * 03[i] * ( 1 - 03[i] );

// Delta wij = Ndj oi

for ( i=O; i<HiddenUnitNo; i++ ) { for( sum = O, j=O; j < OutputUnitNo; j++){

dw321j][i] = BPNPar.Eta * d31j] * 02[i] + BPNPar.Alpha

w32[j] [i] += dw32[j] [i]; *dw321j][i];

sum += d31j] * w321j][i]; }

// fi = ( Sigma wji di)j’(i,j)

} d2 [i] = 02[i] * (1 - o2[i]) * sum;

for( i = O; i<OutputUnitNo; i++){

dbias3[i] = BPNPar.Eta * d3[i] +BPNPar.Alpha * dbias3[i]; bias3[i]+= dbias3[i];

> // Delta wij= Ndj oi

for( i=O; i<InputUnitNo; i++ )

for( j=O; j<HiddenUnitNo; j++){

33

dw2lljI [i] = BPNPar.Eta * d21jl * ol[p][i] + BPNPar.Alpha * dw2llj][i];

} w2llj][i]+= dw2llj][i];

for( i=O; i<HiddenUnitNo; i++ ){ dbias2[i] = BPNPar.Eta * d2[i] +BPNPar.Alpha * dbias2[i];

1 bias2[i]+= dbias2[i];

1 // Fin de Backpropagation

// Despliega Estado

void state (int p){

int i; // contador de ciclo

printf( ‘ ‘ %4d-> ’ ’ ,p+l); propagat ion (p) ; for( i=O; i<OutputUnitNo; i++ )

fputc(’\n’,stdout); printf( ‘ ‘ 7,s. 3f ’ ,03[i]);

1 // fin de despliega estado

// Lee datos de un archivo void read file( char *name) {

int i,j; // contadores de ciclo ... FILE *fp,*op; // apuntadores a los archivos de datos. .. char nfile[80] = ‘ ‘ ’ ’ ;

// Se abre el archivo if( (fp =fopen(name, ‘ ‘ r ’ ’))==NULL){

fprintf(stderr, ‘ ‘%S : E r r o r al abrir archivo! ! \n’ ’,name); exit(-1);

}

34 3. Implantación

printf(‘ ‘Nombre del archivo de pesos : ”); gets(nfi1e); if(strcmp(nfile,‘ ‘ ’ ’) != O)

{

if( (op =fopen(nfile,‘ ‘ r b ’ ’))==NULL) {

fprintf(stderr, ‘ ‘%S : Error al abrir arch ivo ! ! \n’ ’ ,nfile); exit (-1);

1 fread(&BPNPar,sizeof(parms),l,op); fread(ol,sizeof(float),MaxPatternNo*InputUnitNo,op); fread(02,sizeof(float),HiddenUnitNo70p); fread(o3,sizeof(float),OutputUnitNo,op); fread(t,sizeof(float),MaxPatternNo*OutputUnitNo,op); fread(wZl,sizeof(float),HiddenUnitNo*InputUnitNo,op); fread(dw2l,sizeof(float),HiddenUnitNo*InputUnitNo,op); fread(w32,sizeof(float),OutputUnitNo*HiddenUnitNo,op); fread(dw32,sizeof(float),OutputUnitNo+HiddenUnitNo,op); fread(bias2,sizeof(float),HiddenUnitNo70p); fread(dbias2,sizeof(float),HiddenUnitNo,op); fread(bias3,sizeof(float),OutputUnitNo,op); fread(dbias3,sizeof(float),OutputUnitNo,op);

1 else

BPNPar.InUnitNo = InputUnitNo; BPNPar.HiUnitNo = HiddenUnitNo; BPNPar.OutUnitNo = OutputUnitNo; BPNPar.MaxPatNo = MaxPatternNo; BPNPar.learning-patternno = 20; BPNPar.iter = O; BPNPar.Eta = 0.90; BPNPar.Alpha = 0.43; BPNPar.ErrorFunc = 0.02; BPNPar.Wmin = -0.30; BPNPar.Wrrlax = 0.30;

1

35

// Se leen los datos de aprendizaje

fread (&BPNPar.learning-patternno,sizeof(int),l,fp); printf( \n#patrones de

aprendizaje :%ld\n’ ’,BPNPar.learning-patternno); for( i=O; i<BPNPar.learningpatternno; i++) {

clrscr(); for(j=O; j<InputUnitNo; j++)

for( j=O; j<OutputUnitNo; j++ )

printf( “patron %d\n’ ’,i);

fread(&ol[i]lj],sizeof(float),l,fp);

fread(&t[i]lj],sizeof(float),l,fp);

1 fclose ( fp) ; fclose( op) ;

} // fin de read-file

// Inicializando los pesos

void initialize(void){

int i$; // elontadores de ciclos

// Inicializando los pesos (capa de entrada->capa escondida)

for( i=O; i<HiddenUnitNo; i++ ) for( j=O; j<InputUnitNo; j++ )

w2l[i]lj] = rnd();

// Inicializando los pesos (capa escondida->capa de salida)

for( i=O; i<OutputUnitNo; i++ ) for( j=O; j<HiddenUnitNo; j++ )

w32[i]Ij] = rnd();

// fin de initialize

36 3. Implantación

void asincrona(int iter-actual){

FILE *op; char nfile[80] = ‘ ‘ ’ ’ ,ans = ’ ’; int ascl=-l,asc2=O,i=O,j=O;

if(kbhit()) {

ascl=getch(); if(kbhit ())

asc2=getch();

if(ascl==-l && asc2==O)

if(ascI==O)

}

return;

{ switch(asc2) {

case 60 : // F2 : Salvar tabla de pesos en disco ... printf( ‘ ‘Nombre del archivo de pesos : ’ ’); gets(nfi1e); if( (op =fopen(nfile, ‘ ‘ wb’ ’))==NULL) {

fprintf(stderr,‘ ‘ %S : Error a l abrir

exit(-I); archivo ! ! \n ’ ’ ,nfile);

1 BPNPar.iter = iter-actual; fwrite(&BPNPar,sizeof(parms),l,op); fwrite(ol,sizeof(float),MaxPatternNo*InputUnitNo,op); fwrite(o2,sizeof(float),HiddenUnitNo,op); fwrite(03,sizeof(float),0utputUnitNo70p); fwrite(t,sizeof(float),MaxPatternNo*OutputUnitNo,op); fwrite(w2l,sizeof(float),HiddenUnitNo*InputUnitN0,0p); fwrite(dw21,sizeof(float),HiddenUnitNo*InputUnitN0,0p); fwrite(w32,sizeof(float),OutputUnitNo*HiddenUnitNo,op);

37

fwrite(dw32,sizeof(float),OutputUnitNo~HiddenUnitNo,op); fwrite(bias2,sizeof(float),HiddenUnitNo,op); fwrite(dbias2,sizeof(float),HiddenUnitNo,op); fwrite(bias3,sizeof(float),OutputUnitNo,op); fwrite(dbias3,sizeof(float),OutputUnitNo,op); fclose( op) ; printf( ‘ ‘Salir (S/N) ?’ ’); do ans = toupper(getche()); while( ans != ’S’ && ans != ’N’ ); if( ans == ’S’ )

exit(O); break;

for( i=O; i<HiddenUnitNo; i++ ) case 61 : // F3 : Guara!ar tabla de pesos ...

{ fprintf(stdpm,‘ ‘Pesos de entrada-:>oculta nodo

for( j=O; j<InputUnitNo; j++ )

fprintf(stdprn, ‘ ‘ \n’ ’);

: %2d\n ’ ,i+l);

fprintf(stdprn, ‘ ‘%+l. 4f ’ ,w21[i:I b]);

}

{ for( i=O; i<OutputUnitNo; i++ )

fprintf(stdprn, ‘ ‘Pesos de oculta->salida nodo

for( j=O; j<HiddenUnitNo; j++ )

fprintf(stdprn, ‘ ‘ \n’ ’);

:%2d\n’ ,i+l);

fprintf(stdpm,‘ ‘%+1.4f ’,w32[i]b]);

} break;

default: printf( ‘ ‘\unknown. . . \n ’);

// fin del switch

// fin de asincrona

38 3. Implantación

Capítulo 4

Conclusiones

El simulador de BPN se utilizó para entrenar una red que clasifica patro- nes. En este caso utilizamos los patrones correspondientes a los caracteres numéricos ( O al 9).

En la grafica vemos los resultados de la función de e:rror en la clasifica- ción de los 10 patrones para la red contra el número de iteraciones en el entrenamiento.

O 500 1000 1500 21000 2500

Figura 4.1: Función de error durante el entrenamiento de la red.

39

40 4. Conclusiones

Bibliografía

[l] Freeman, James. Skapura, David. Neural Networks. .Algorithms , Appli- cations, and Programming Techniques. Addison Wesley, 1991.

[2] Gonzalez, Rafael. Woods, Richard. Digital Image Processing. Addison Wesley, 1992.

[3] Hecht-Nielsen, R. Neurocomputing. Prentice Hall, 19190.

[4] Michalski, Ryszard. Carbonell, Jaime. y Mitchell, Tom. Machine Lear- ning: An Artificial Intelligence Approach. Tioga Publishing Company, 1983.

[5] Rich, Elaine. Knight, Kevin. Artificial Intelligence. Ed. McGraw Hill, 1991.

[6] Weber, David. Detecting T e d Regions Using Cellular Automata. En The C Users Journal, Agosto 1993.

[7] Winston, Patrick H. Artificial Intelligence. Addison Wesley, 1992.

41

42 BIBLIOGRAF~A

Apéndice A

Extraccción de Regiones

A continuación, el codigo fuente de un extractor de regiones (patrones) de un archivo gráfico para SU posterior uso con el simulador de IBPN anteriormente descrito.

A.l Definiciones para el manejo de archivos gráficos

// """"""""_ ~

// // Definiciones de Proposito General.

# i f ndef "ZONEH #include "zone. h" #endif

# i f ndef "SXTPTHNG-H #define 3XTPTHNG-H

#if ndef NULL # i f def ined(L-TINY--) I I def ined(-SMALL--) I I def in~ed(-JlEDIlJ"-) #define NULL O #e l se #define NULL OL #endif

43

44 A. Extmccción de Regiones

#endif

#define FALSE O #define TRUE 1

#define FAR far #define NEAR near #define LONG long #define VOID void #define PASCAL pascal

#if !defined( NOMINMAX && !defined( --cpluSpluS

# i fndef m a x #define max(a,b) (((a) > (b) ? (a) : (b)) #endif

#if ndef min #define min(a,b) (((a) < (b)) ? (a) : (b)) #endif

#endif /* NOMINMAX */

#define MAKELONG(a, b) ((LONG) ( ((WORD) (a) I ( ( (DWORD) ( (WORD) (b) ) ) << 16) #define LOWORD(1) ((WORD) (1)) #define HIWORD(1) ((WORD) (((DWORD) (1) >> 16) & OxFFFF)) #define LOBYTE(w) ( (BYTE) (u) #define HIBYTE(w) ((BYTE) (((WORD) (u) >> 8) & OxFF))

typedef int BOOL; typedef unsigned char BYTE; typedef unsigned int WORD; typedef unsigned long DWORD; typedef char near *PSTR; typedef char near *NPSTR; typedef char far *LPSTR; typedef BYTE near *PBYTE;

45 A.l. Definiciones para el manejo de archivos gráficos

typedef BYTE f a r *LPBYTE; typedef int near *PINT; typedef int f a r * L P I N T ; typedef WORD near *PWORD ; typedef WORD f a r *LPWoRD ; typedef long near *PLONG; typedef long f a r *LPLONG; typedef DWORD near *PDWORD; typedef DWORD far *LPDWORD; typedef void far *LPVOID;

#ifndef WIN-INTERNAL typedef WORD HANDLE ; typedef HANDLE HWND ; #endif

typedef HANDLE *PHANDLE ; typedef HANDLE NEAR *SPHANDLE ; typedef HANDLE FAR *LPHANDLE; typedef HANDLE GLOBALHANDLE ; typedef HANDLE LOCALHANDLE ; typedef int (FAR PASCAL *FARPROC) O ; typedef int (NEAR PASCAL *NEARPROC) () ;

typedef HANDLE HSTR; typedef HANDLE HICON; typedef HANDLE HDC; typedef HANDLE HMENU; typedef HANDLE HPEN ; typedef HANDLE HFONT ; typedef HANDLE HBRUSH; typedef HANDLE HBITMAP ; typedef HANDLE HCURSOR; typedef HANDLE HRGN; typedef HANDLE HPALETTE;

typedef DWORD COLORREF ;

46 A. Extraccción de Regiones

#ifndef WIN-INTERNAL typedef struct tagRECT

int left; int top; int right ; int bottom;

} RECT; #endif

typedef RECT *PRECT; typedef RECT NEAR *NPRECT ; typedef RECT FAR *LPRECT;

typedef struct tagPOINT {

int x; int y;

} POINT; typedef POINT *PPOINT ; typedef POINT NEAR *NPPOINT; typedef POINT FAR *LPPOINT;

// ~

// Definition del Encabezado de un Mapa de Bats. //

typedef struct tagBITMAP {

int bmType; int bmWidth; int bmHeight ; ink bmWidthBytes; BYTE bmPlanes; BYTE bmBitsPixe1; LPSTR bdits ;

} BITMAP; typedef BITMAP *PBITMAP ;

A.I. Definiciones para el manejo de archivos gráficos 47

typedef BITMAP NEAR *NPBITMAP; typedef BITMAP FAR *LPBITMAP;

typedef struct tagRGBTRIPLE { BYTE rgbtBlue; BYTE rgbtGreen; BYTE rgbtRed;

} RGBTRIPLE ;

typedef struct tagRGBQUAD { BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; BYTE rgbReserved;

} RGBQUAD;

// . .

/ f Estructuras para definir DIBs.

typedef struct tagBITMAPCOREHEADER { //

DWORD bcSize; /* used to get to color table */ WORD bcWidth; WORD bcHeight ; WORD bcPlanes; WORD bcBitCount;

} BITMAPCOREHEADER; typedef BITMAPCOREHEADER FAR *LPBITMAPCOREHEADEEl; typedef BITMAPCOREHEADER *PBITMAPCOREHEADER;

typedef struct tagBITMAPINFOHEADER{ DWORD biSize; DWORD biWidth; DWORD biHeight; WORD biplanes; WORD biBitCount;

48 A. Extraccción de Regiones

DWORD biCompression; DWORD biSizeImage; DWORD biXPelsPerMeter; DWORD biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant;

} BITMAPINFOHEADER;

typedef BITMAPINFOHEADER FAR *LPBITMAPINFOHEADER; typedef BITMAPINFOHEADER *PBITMAPINFOHEADER;

//

// // Constantes para el Campo biCompression.

#define BIRGB OL #define BIRLE8 1L #define BIRLE4 2L

typedef struct tagBITMAPINF0 { BITMAPINFOHEADER bmiHeader; RGBQUAD bmiColors 111 ;

) BITMAPINFO; typedef BITMAPINFO FAR *LPBITMAPINFO; typedef BITMAPINFO *PBITMAPINFO;

typedef struct tagBITMAPCOREINF0 { BITMAPCOREHEADER bmciHeader; RGBTRIPLE bmciColors [l];

} BITMAPCOREINFO ; typedef BITMAPCOREINFO FAR *LPBITMAPCOREINFO ; typedef BITMAPCOREINFO *PBITMAPCOREINFO;

typedef struct tagBITMAPFILEHEADER { WORD bfType; DWORD bf Size; WORD bfReservedl;

A.I. Definiciones para el manejo de archivos gráficos 49

WORD bfReserved2; DWORD bf0ffBits;

} BITMAPFILEHEADER; typedef BITMAPFILEHEADER FAR *LPBITMAPFILEHEADER; typedef BITMAPFILEHEADER *PBITMAPFILEHEADER;

// Definicion del encabezado para un archivo PCX. //

#define DOSN 8

typedef struct PCXWin PCXWin;

struct PCXWin { WORD xul,

xlr , yul J

ylr ; 1;

typedef struct PCXhdr PCXhdr;

struct PCXhdr

BYTE flag,Ver,Encod,Bitspp; PCXW in Wndw ; WORD HDPI ,VDPI ; BYTE ColorMap[481 ,Reserved,NPlanes; WORD Bytespl,PalletteInfo,HScrSize,VScrSiz:e; BYTE Filler C541 ;

50 A. Extraccción de Regiones

//

// // Prototipos de Funciones.

void finding-out(PCXhdr &mgi,FILE *fp,int show = 0); void pcxread-line (BYTE *linep ,FILE *f p , int bpline) ; void IniciaGraf icos (void) ; void CierraGraf icos (void) ; void despliega(BYTE * , int , int , WORD , BYTE *I ; void mascarada(BYTE *ind) ; void cut-vertical-lines(BYTE *image ,int dx ,int dy,BYTE *I ; void blockzones (BYTE *image, int dx , int dy ,BYTE * I int coarseness) ; int vecindario(BYTE pixe1,int pos,BYTE E,BYTE 0,BYTE N,BYTE S,BYTE *MASK); void sequence-zones (BYTE * ,int , int ,int ,int& ,BYTE * ZONE

int ition (BYTE zona,BYTE t MASK); int vec (BYTE *here , BYTE *vecino ,int pos ,HEADING dir ,BYTE *MASK) ; void act (intt pos , int& ix , int& iy , int& dir ,HEADING nva-dir) ; int extract-zone (BYTE *image ,int dx,int dy ,int X,int Y,

** ,WORD) ;

ZONE *zone-ptr ,BYTE *MASK ) ;

#endif // "SXTPTHNG-H

A.2 Definiciones para la extracción de zonas // // Z0NE.H : // definiciones,tipos y prototipos para extraccion de zonas. //

A.8. Definiciones gam la extmcción de zonas 51

# i f ndef "ZONEH #define "ZONEH

#define SAMPLE200X 8 // frecuencia de muestreo x para una imagen

#define SAMPLE-200-Y 10 // frecuencia de muestreo y para una imagen

#define MAXALLOC Oxf€OO // tamao maximo para malloc.

// m 0 PPP.

// m 0 PPP.

//

// // corte vertical de lineas.

#define CUT-VERTICAL-LINES 1 // corte vertical de Eineas (ON/OFF) #define VERTICAL-LINE-SIZE 50 // longitud minima de linea vertical ,200 PPP.

//

// """"""_"" ~

/ / formacion de bloques.

//#define WHITE Ox00 // Color blanco en la muestra. //#define BLACK Oxfl// Color negro en la muestra. #define ALIVE Ox00 // Aun con vida. #define SICK !ALIVE // Casi blanco. #define PREGNANT !ALIVE // Casi blanco. #define LIFESCORE 2 // No esta aislado. #define DEATHSCORE O // No tiene vecinos.

//

// // secuenciamiento.

typedef struct

int x1,y1,pos1,x2,y2,pos2,sizex; } ZONE;

52 A . Extraccción de Regiones

#define MINXZONE 4 // extension x minima permisible para zona. #define MIN-YZONE 2 // extension y ibidem. Medidas en bits.

typedef enum

GOING-UP, GOINGRIGHT, GOINGDOWN, GOINGLEFT

{

} HEADING;

#define MAX-ZONES 43 // numero maximo de zonas. #define COLUMN-MAJOR 1 // orden de zonas con las columnas dominando. #define ROW-MAJOR 2 // orden de zonas con las filas dominando.

//

// // prototipos.

int zone(int coarsenessjnt order);

A.3 Funciones para la segmentación de regio- nes

// ;; PCXFN.CPP : // Contiene las funciones para el tratamiento previo de la imagen de texto // a ser reconocida. // ~ ""-"---

#ifndef "STDIO-H #include <stdio .h>

A.3. Funciones para la segmentación de regiones 53

#endif

#if ndef "STRINGH #include <string. h> #endif

#ifndef "STDLIBH #include <stdlib . h> #endif

#ifndef "CONIOH #include <conio. h> #endif

#if ndef --GRAPHICS-H #include <graphics. h> #endif

#ifndef "MEMH #include <mem. h> #endif

#if ndef "IOSTREAM-H #include <iostream. h> #endif

#if ndef "SXTPTHNG-H #include "sxtpthng . h" #endif

#if ndef "ZONEH #include "zone. h" #endif

// // La siguiente funcion identifica un archivo grafico PCX, y lee su // encabezado en una estructura del tipo apropiado. //

54 A. Extraccción de Regiones

void f inding-out (PCXhdr &mgi ,FILE *fp J int show) {

rewind(fp) ; f read (&mgi , sizeof (PCXhdr) , 1 , fp) ;

if(show) //Desplegar informacion del archivo? {

p r i n t f ( “ \ n \ n ” ) ; p r in t f ( ‘ ‘Bandera. . . . . . . %x\n’ ’ ,mgi . f l ag ) ; pr in t f ( ‘ ‘Version. . . . . . . %u\n’ ’ ,mgi .Ver) ; pr in t f ( ‘ ‘ Codif icacion. . %x\n ’ ’ y mgi . Encod) ; pr in t f ( ‘ ‘Bits ppxl. . . . .%u\. ’ ’ ,mgi. Bitspp) ; printf(“Ventana.xu1. ..%u\n”,mgi.Wndw.xul); p r in t f ( ‘ ‘Ventana. yul. . . %u\n’ ’ ,mgi . Wndw .yul) ; pr in t f ( ‘ ‘Ventana. x l r . . . %u\n’ ’ ,mgi . Wndw . x l r ) ; pr in t f ( ‘ ‘Ventana. y l r . . .%u\n’ ’ ,mgi . Wndw . y l r ) ; pr in t f ( ‘ ‘HDPI . . . . . . . . . .%u\n’ ’ ,mgi .NPlanes) ; pr in t f ( ‘ ‘ VDPI . . . . . . . . . . %u\n’ ’ ,mgi .Bytespl) ; pr in t f ( ‘ ‘Planos. . . . . . . . %u\n’ ’ ,mgi .NPlanes) ; printf(“Bytesp1 . . . . . . . %u\n”,mgi.Bytespl); p r in t f ( ‘ ‘Pa1le t te Info . .%x\n”,rngi.PalletteInfo); p r in t f ( ‘ ‘HScrSize . . . . . . %u\n’ ’ ,mgi . HScrSize) ; pr in t f ( ‘ ‘ VScrSize . . . . . . %u\n’ ’ ,mgi .VScrSize) ;

} // Informacion mostrada } // Archivo encontrado

// ”” ~

/ / Lee una linea codificada de escaneado (Todos los planos de color) de // un archivo imagen con formato PCX y escribe los datos decodificados // a un buffer de linea de escaneado. // ~ ”” ~ ~ ” _ ~

void pcxread-line (BYTE *linep,FILE *fp, int bpline) // apuntador al buffer de linea de

escaneo // apuntador al archivo de imagen // # bytes por linea.(pkanos de color).

A.9. Funciones para la segmentación de regiones 55

i int data; // Byte de datos de la Imagen int count; // Conteo de repeticion del byte de Imagen int off set = O; // Oflset en la linea de escaneado memset (linep,OxFF,bpline) ; while (off set < bpline) // Decodificar linea de escaneado {

data = getc(fp) ; // Obtener el siguiente byte

// Si dos bits mas altos del byte estan establecidos, los seis bit mas // bajos muestran cuantas veces duplicar el siguiente byte

if ((data & OxcO) == OxcO) {

count = data & Ox3f; // Mascara de conteo de repeticion data = getc(fp) ; // Obtener el siguiente byte memset (linep, data, count) ; // Duplicar byte linep += count; offset += count;

1 { else

*linep++ = (BYTE) data; // Copiar byte off set++ ;

} 1

1

void IniciaGraf icos O {

int Error, Manejador, GraficoModo; Mane j ador = DETECT; //GraficoModo=CGA; // 640 * 200 pixeles initgraph( &Manejador, tGraficoModo, 1; Error = graphresult 0 ; if( Error ! = grOk )

{

56 A. Extraccción de Regiones

printf ( ' ' Error al intentar usar Grficos: %s\n' ' , grapherrormsg(Err0r) ;

exit( 1 1 ; 1 else

cleardevice 0 ; } // Fin de IniciaGraficos

void CierraGraf icos 0

closegraph0 ; // Modo tezto restaurado printf(" De regreso al Sistema...");

} // Fin de CzerraGraficos

void mascarada(BYTE *ind) // Inicia el arreglo de mascaras 2An

{ BYTE *ap = fnd;

for (int i = O ; i < DOSN; i++)

ap = ind; *ap++ = 1 <<i;

// for(i = U; i < DOSN; i++) // printf("%;d\n",*ap+S); }

void despliega(BYTE *scline,int x,int y,WORD scansz, BYTE *mascaras> {

BYTE dato ; BYTE *indpt; WORD walker = O; int ind;

while ( walker++ < scansz

A.3. Funciones para la segmentación de regiones 57

dato = *scline++; for(ind = 7, indpt = (mascaras + 7u) ; ind

>=O;ind----,indpt----) {

if((dato & *indpt) == *indpt) putpixel (x++, y, WHITE) ;

else putpixel (x++, y, BLACK) ;

) // Despliega

// // funcion : static void cut-vertical-lines(BYTE *image,rint dx,int dy, BYTE *) I / // Remueve lineas verticales de la muestra. El proposito de esta funcion es // desenmarcar el texto. Esto se logra al remover las lineas verticales. Tratar // de remover las lineas horizontales es peligroso porque tambien se puede // remover texto. // parametros : apuntador al bufler con la imagen muestreada , las extensiones // x/y del bufler y el arreglo de mascaras para comparar bit a bit // regresa : nada. //

void cut-vertical-lines (BYTE *image, int dx , int dy ,BYTE *MASK) {

int x , y, count, y í , ind; BYTE *ptr , *qtr;

forb = O ; x < dx ; x++) // escanear imagen de izquierda a derecha.

{

58 A . Extraccción de Regiones

ptr = image + x; for (ind =7 ; ind >= O; ind-- --)

count = o; for(y = O ; y < dy ; y++, ptr += dx) { // escanear hacia arriba y abajo contando

// lineas de pixeles. if( (*ptr & MASKCindl == MASK Cindl) // Si es blanco.

count = o; else

count++ ; if(count >= VERTICAL-LINE-SIZE) // Linea vertical a la

vista.. . {

for (y1 = y , qtr = ptr; count > O ; count-- --,

*qtr = *qtr I MASK [indl ; // blanqueando hacia Y 1" " , qtr -= dx)

arri bu.. . count = O; // reseteamos el contador.

) // fin del if count ... } // fin de for y = O...

} // fin de for ind ... ) // fin de for x = O...

} // fin de cut-vertical-lines.

// ~

/ / funcion : static void blockzones(BYTE *image,int dx,int dy,BYTE *MASK, // int coarseness); // Utiliza un automata celular para crear bloques de la imagen. Cada bloque // representa una region de texto. El proceso consta de dos pasos. Primero, se // usa el automata celular para esbozar la region. Como segundo paso, usar el // parametro coarseness (O -5 ) para coalesce las regiones. Un valor mayor del // parametro producira regiones mas grandes.

A.3. Funciones para la segmentación de regiones 59

// parametros : apuntador al buffer de la imagen, extensriones x/y del bu$er Y // coarseness de la zona (0-5). // regresa : nada. //""""""~"""~"""

void blockzones (BYTE *image, int dx , int dy , BYTE *MASK, int coarseness { int i,j,x,y,score,cnt; BYTE *line, *pixel, // Apuntadores auxiliares a la Imagen Original. *N, *S, *E, *O, // Vecinos en las 4 direcciones. *nxt img, *nline , *npixel ; // Imagen de estado y a,puntadores

auxiliares.

BYTE frontis = Oxff;

if( (nxtimg = (BYTE *) malloc(dx * dy)) == NUL:L )

cerr << "No hay suficiente memoria para procesar los

return; bloques. . . \nJ ' ;

1 memset (nxtimg ,BLACK, ( d x * dy) ; //iniciamos la im. auxiliar.

for(y = 1, line = image+dx, dine = nxtimg+dx; y < dy -1 ; // keep on...

y++, line += dx, nline += dx) { // Paseando a traves del buffer en busca de vecinos.

for(X = 1, pixel = line+i, npixel =nline+l ; X < dx - 1 ; x++, pixel ++, npixel ++)

{ if(x == 1)

else

if(x == (dx - 2))

O = &frontis;

{

60 A. Extmccción de Regiones

E = &frontis; else {

1 O = pixel - 1; E = pixel + 1;

} N = pixel - dx; S = pixel + dx ;

for (cnt = 7; cnt >= O ; cnt -- --I {

score = O; if( (*pixel & MASKCcntl) == O )

{ score = vecindario (*pixel, cnt , *O, *E, *N , *S ,MASK) ; if(score < LIFE-SCORE)

*npixel = *npixel I MASK Ccntl ; 1

1 ) // fin de for x = l...

} // fin de for y = l... for (pixel=image , npixel=nxtimg; pixel< (image+(dy*dx) ;

pixel++, npixel++) *pixel = *npixel I *pixel; // birth & buy.

if(coarseness <= O) // No se necesita cerrar brechas return ; // coalescence regions, basados en coarseness, i.e. coarseness == 2 // cerrara todas las brechas horizontales/verticales de dos pixeles.

} // fin de blochxones.

int vecindario(BYTE pixe1,int pos,BYTE E,BYTE 0,BYTE N,BYTE S,BYTE *MASK)

int vecinos = O; switch(pos1

case 7 : {

A.3. Funciones para la segmentación de regiones 61

if( (O & MASK COI > == O>

break ;

if( (E & MASK C71) == 0)

break ; default :

if( (pixel & MASKCpos-11) == O>

if( (pixel & MASK[pos+ll) == 0)

break ;

vecinos++;

case 1 :

vecinos++;

vecinos++;

vecinos++;

} // fin del switch if( (N & MASKCposl) == O>

vecinos++; if( (S & MASK [pos] == O)

vecinos++; return vecinos;

} // fin de vecindario.

// // funcion : static void sequence-zones(BYTE *image,in;t dx,int dy,int order) // Extraer zonas del buffer, ponerlas en zone-list, actualizar zone-count y // secuenciar las zonas para ponerlas ya sea en orden de lectura COL UMN-MA JOR o // RO W-MAJOR. // parametros : apuntador al buffer de la imagen, las extensiones x / y de la // imagen en el orden del bufler, COLUMN-MAJOR o ROW-MAJOR y los // arreglos de mascaras de bits para comparacion y el arreglo con // los datos de las zonas. // regresa : nada. //

void sequencezones(BYTE *image,int dx,int dy,int order,

**zona, WORD dimx) int& zone-count,BYTE *MASK,ZONE

62 A . Extraccción de Regiones

{ int x,y,i,j,index,fudge-x,fudge-y; BYTE *ptr;

for(y = 1 , zone-count = O ; // Contando del inicio de la img. y < dy && zone-count < MAX-ZONES ; // Hasta el f in y no

y += MIN-YZONE) // Avanzar una dist. min de patron. exceder max z.

{ // extraer zonas de bloques de imagenes en orden 9. ptr = image + (y * dx) ; for( x = O ; x < (dimx/8) ; x ++ )

if( (* (ptr + x) 1 ! = OxFF ) // no es una region blanca.. . {

if( zone-count >= MAX-ZONES)

zona[zone-count] = new ZONE; zona [zone-count] +x1 = 0 ; zona [zone-count1 -+y1 = O ; zona[zone-count1 +pos1 = O; zona [zone-count] +x2 = O; zona [zone-count1 -+y2 = O ; zona [zone-count1 +pos2 = O ; zona [zone-count1 -+sizex = O; if(extractzone(image,dx,dy,x,y,zona~zone~countl ,MASK))

break ;

zone-count++; // obtener zona. } f / fin de if *ptr.. .

1 ) // fin de sequence-xones.

. .

// Funcion : ition. // Encuentra la posicion en donde empezar en el byte en caso de que en el // byte existan por Io menos 2 bits no blancos consecutivos. //

"" .~ ~" ~

int ition (BYTE zona,BYTE * MASK)

{ int ind = 7 , pos = 7, prim-ciclo = 1, cant = O; do {

A.3. Funciones para la segmentación de regiones 63

if( (zona & MASK Cindl ) == BLACK )

{ if(cant == o) // Inicio de 1 er. cadena de 0”s

cant ++ ; pos = ind;

} else

if(cant ! = O> prim-ciclo = O; // Ya no es la l e r . cadena de O’s.

} // Mientras estemos en zona y no terminemos la l a . cad. de O’s while( (----ind >= O) && prim-ciclo ; if( cant > O

else return pos;

return WHITE;

// //

// // vec. regresa el valor del vecino indicado por dir.

// int vec(BYTE *here,BYTE *vecino,int pos,HEADING dir,BYTE *MASK) { // Pregunta por el tipo de vecino ...

switch (d i r ) {

case GOING-UP : case GOINGDOWN :

return ( *vecino & MASKCposl ; case GOINGLEFT :

if(pos == 7 )

else return ( *vecino & MASKC01 ;

return ( *here & MASKCpos+ll ; case G O I N G A I G H T :

if(pos == 0) return ( *vecino 8 MASKC71 1 ;

64 A . Extraccción de Regiones

else return ( *here & MASKCpos-11 ;

1 } // Fin de vec ...

//""""""""""""" // funcion : static int extract-zone(BYTE *image,int dx,int dy,int x,int y, // ZONE *zone-ptr);

// Extrae una region rectangular del bufler empezando en un punto. Lo hace // cruzando el perimetro, grabando las dimensiones maximas y minimas

// Si la region es suficientemente grande para ser significante, se salva como // una zona y se blanquea para no ser reconsiderada posteriormente. // parametros : apuntador al bufer de la imagen y las extensiones dx/dy del // buffer. x e y apuntan al principio de la zona de extraccion. // ap. al almacenamiento para la zona y el arreglo de Mascaras // regresa : 1 si es una zona O si no.

//

X/Y *

int extract-zone (BYTE *image,int dx,int dy,int x,int y, ZONE *zone-ptr,BYTE *MASK)

{ int ix,iy,minx,miny,posizq = O,

HEADING dir ; // direccion actual. BYTE *previous , *next, *here , // apuntadores a buafer.

int xp = 15, yp = 1;

maxx,maxy,posder = 0,pos ,posini; // variables de perimetro y

*ant , *sig, frontis = WHITE; // y la frontera imaginaria.

BYTE BLANC [SI = { OxOl,OxO3 , 0x07 , OxOF , OxlF , Ox3F , Ox7F , OXFF) ; BYTE BLAND [S] = {OXFF , OxFE , OxFC , OxF8 , OxFO , OxEO , OxCO , 0x80) ;

minx = maxx = ix = x; // preestablecer min/max x/y, miny = maxy = iy = y ; // valores de perimetros dir = GOING-UP; // y direccion de inicio. pos = ition ( *(image + x + y * dx) , MASK ) ; if( pos == WHITE I I pos < O)

return O; // No hay suficientes ptos pireg.

A.3. Funciones para la segmentación de regiones 65

// De otra forma, empezamos a escanear la imagen. pos in i = posder = posizq = pos;

do // recorrer el perimetr0,grabando min/max de la reg. rect. {

i f ( ix == minx %% pos > posizq)

i f ( ix < minx) // actualizar min/max. posizq = pos;

{ minx = i x ; posizq = pos;

} i f ( ix == maxx %% pos < posder)

i f ( ix > maxx)

maxx = i x ; posder = pos;

posder = pos;

{

1 i f ( iy < miny)

miny = i y ; i f ( iy > maxy)

maxy = i y ;

here = image + ( i y * dx) + i x ; // donde estamos ?

i f ( iy > O %% i y < dy) {

}

previous = here - dx; next = here + d x ;

i f ( iy == O) {

previous = &fron t i s ; next = here + d x ;

1

66 A . Extmccción de Regiones

if(iy == dy) {

previous = here - dx; next = &frontis;

}

if(ix > 0 && ix < dx)

ant = here - I ; sig = here + 1;

{

1 if(ix == 0)

{ ant = &frontis; sig = here + I ;

1 if(ix == dx) {

}

ant = here - 1; sig = &frontis;

switch (dir) // basados en la direccion actual, { / / buscar la nueva direccion.

case GOING-UP : if( ix > O &¿I vec(here,ant ,pos ,GOING-LEFT,MASK) ==

BLACK {

if(pos == 7 )

ix-- -- ; pos = o; 1 else

dir = GOINGLEFT; XP-- ” ; break ;

pos++ ;

A.3. finciones para la segmentación de regiones 67

1

{

i f ( iy > O && vec(here,previous,pos,GOING-UP,MASK) == BLACK )

iY-- --; d i r = GOING-UP; YP-- --; break ;

1

{

i f ( ix < dx-I && vec(here,sig,pos,GOING-RIGHT,MASK) == BLACK )

if(pos == O> {

1 ix++; pos = 7;

else

d i r = GOING-RIGHT; xp++ ; break ;

POS-- --;

1 if( iy < dy-1 && vec(here,next,pos,GOING-DOWN,MASK)

== BLACK )

{ iy++ ; d i r = GOING-DOWN; YP++ ;. break ;

1 break ;

i f ( iy > O && vec(here,previous,pos,GOING-UP,MASK) == case GOINGAIGHT :

BLACK )

{ iY-- --; d i r = GOING-UP; YP-- --;

68 A. Extmccción de Regiones

break ; }

{

if(ix < dx-1 && vec(here,sig,pos,GOING-RIGHT,MASK) == BLACK )

if(pos == O) {

1 ix++; pos = 7 ;

else

dir = GOINGRIGHT; xp++ ; break ;

POS" " ;

1 i f ( iy < dy-1 && vec(here ,next ,pos ,GOING-DOWN,MASK)

== BLACK )

{ iy++ ; d i r = GOINGDOWN; yp++ ; break ;

} if( ix > O && vec(here,ant,pos,GOING-LEFT,MASK) ==

BLACK {

if(pos == 7)

{

1 ix-- --; pos = O;

else

dir = GOINGLEFT; XP" --; break ;

pos++ ;

} break ;

case GOINGDOWN :

A.3. finciones para la segmentación de regiones 69

if (ix < dx-1 && vec (here , sig ,pos , GOING-RIGHT ,MASK) == BLACK )

I if(pos == O) {

1 ix++; pos = 7;

else

d i r = GOING-RIGHT; xp++ ; break ;

POS" --;

1

{

i f ( iy < dy-1 && vec(here ,next ,pos ,GOING-DOWN,MASK) == BLACK )

iy++ ; d i r = GOING-DOWN; yp++ ; break ;

}

{

if( ix > O && vec(here ,ant ,pos,GOING-.LEFT,MASK) == BLACK

if(pos == 7)

iX" " {

1 ; pos = o;

else

dir = GOING-LEFT; XP" --; break ;

pos++ ;

1 if(iy > O && vec(here ,previous,pos ,GOING-UP,MASK) ==

BLACK {

iY-- --;

70 A . Extmccción de Regiones

dir = GOING-UP; YP" --; break ;

1 break ;

if( iy < dy-1 && vec (here ,next ,pos , GOING-DOWN ,MASK) case GOINGLEFT :

== BLACK {

iy++ ; dir = GOINGDOWN; yp++ ; break ;

}

{

if( ix > O && vec(here,ant,pos,GOING-LEFT,MASK) == BLACK

if(pos == 7) {

} ix----; pos = O;

else pos++ ;

dir = GOINGLEFT; XP" " ; break ;

} if(iy > O && vec(here,previous,pos,GOING-UP,MASK) ==

BLACK {

iY" -- ; dir = GOING-UP; YP" --; break ;

1 if(ix < dx-1 && vec(here ,sig,pos ,GOING-RIGHT,MASK)

== BLACK )

{

A.3. Funciones para la segmentación de regiones 71

if(pos == 0) {

1 ix++; pos = 7;

else

d i r = GOING-RIGHT; xp++ ; break ;

POS" --;

} break ;

1 // fin del swatch.

int megalong = maxx - minx + 1;

fo r ( iy = miny,here = image + miny*dx + minx, next = image + miny*dx + maxx;

{ i y <= maxy ; iy++, here += dx , next += dr)

if( megalong > 2 memset ( here + 1, OxFF , maxx - minx - 1 ; //

blanquear la region. if( megalong > 1

*here = *here 1 BLANCCposizql ; *next = *next I BLAND Cposderl ;

1 if( ( (maxx - minx 1 < 1 ) && ( (posizq - postder + 1) <

MINXZONE return O ;

if( (maxy - miny + 1) < MIN-YZONE ) return O; // suficientemente grande?

zone-ptr+xI = minx; // salvar la zona. zonept r -sy l = miny; zoneptr-sposl = posizq; zone-ptr-sx2 = maxx; zone_ptr+y2 = maxy;

72 A . Extmccción de Regiones

zone_ptr-+pos2 = posder; zone-ptr+sizex = O ;

switch( maxx - minx + 1 1 {

case 1 : zone-ptr+sizex = posizq; break ;

zone-ptr+sizex = posizq; zone-ptr+sizex += posder; break ;

default : if( (maxx - minx + 1) >= 3 1

case 2 :

{ zone-ptr+sizex += 8 * (maxx - minx zone-ptr+sizex = posizq; zone-ptr-ssizex += posder;

1 break ;

} return I ;

} // fin de extract-zone / f Fan de Archivo

1) ;

A.4 Funciones de escalamiento y misceláneas

En esta sección detallamos las funciones usadas para escalar los patrones obtenidos a un tamaño estándar, as; como otras necesarias para guardar los patrones en un archivo adecuado.

#ifndef "STDIO-H #include <stdio .h> #endif

#ifndef "STRING-H #include <str ing.h>

A.4. finciones de escalamiento y misceláneas 73

#endif

#if ndef "STDLIBH #include <stdlib .h> #endif

#if ndef --CONIOH #include <coni0 . h> #endif

#if ndef "CTYPE-H #include <ctype. h> #endif

#if ndef --GRAPHICS-H #include <graphics .h> #endif

#ifndef "MEMH #include <mem. h> #endif

#if ndef "MATH-H #include <math. h> #endif

#ifndef "IOSTREAM-H #include <iostream.h> #endif

#ifndef JXTPTHNG-H #include "sxtpthng. h" #endif

#if ndef "ZONEH #include "zone. h" #endif

74 A . Extraccción de Regiones

#define LNX 7 #define LNY 9

typedef struct {

float patredCLNYl CLNXl ; unsigned lx , l y ; unsigned sa l ida ;

} patron;

typedef s t ruct {

float base C701 C501 ; unsigned l x , ly ;

} patbase;

void trans(patbase *pbase,ZONE *zona,BYTE *MASK,BYTE *image,int dx) ; float radio(float SzOr , float SzNw) ; unsigned redondo( float test ; void despliega(patbase *phase, unsigned o f f s e t = O) ; / /vo id despliega(patron *pat,unsigned offset = O); void reduce (patbase *pbase , patron *pat) ;

int main(int argc , char *aqv C 1 ) {

FILE *fp , *op; // El archivo PCX y el de Patrones. char nomstr C501 = " ' ' , p a t s t r C501 = ' ' " C503 ; PCXhdr mgi; BYTE *mapa,*linsc,

* t ex to ,* l in tx t , MASK C81 ;

char *pcx = NULL; char parml C201; ZONE *zonas [MAX-ZONES] ; int zone-count = O ; WORD dimx ; patbase *pbase ;

A.4. Funciones de escalamiento y misceláneas 75

patron *pats [MAX-ZONES] ; unsigned salida = O;

float teachCl01 ClOl = ( (1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, o . o } ,

(0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, o . o } , (0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, o . o } , (0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, o . o } , (0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, o . o } , (0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, o . o } , (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, o . o } , (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, o . o } , (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 31.0, o . o } , (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0) };

if( argc < 2 {

printf ( ‘ ‘ \n\nNombre del archivo PCX: ’ ’1 ; gets (nomstr) ;

printf ( ‘ ‘realizar filtrado (S/N) ? ’ ’ ; gets (ans) ;

1 { else

strupr( strcpy(ans ,argvC21 ; strcpy (parml , argv C11) ; strcpy (nomstr , strupr (strtok (argv Cll , ‘ ‘ . ’ ’ 1) ; pcx = strtok(NULL,“.”); if(pcx == NULL)

else strcat (nomstr , ‘ ‘ . PCX ’ ’ ;

1 strcpy(nomstr ,parmi) ;

printf ( ‘ ‘ \nNombre del archivo de patrones : ’ ’) ; gets(patstr1;

76 A. Extmccción de Regiones

if ( (fp = f open (nomstr , ‘ ‘ rb’ ’ ) ) == NULL) // El archivo no existe.. .

{ printf ( ‘ ‘\nError al abrir el archivo pcx. . . \n’ ’1 ; exit (O) ;

} // if. .‘ if ((op = f open(patstr, ‘ ‘ wb’ ’1 1 == NULL) // El archivo de pesos { // no se puede abrir. ..

printf ( ‘ ‘ \nError al abrir el archivo de patrones. . . \n’ ’ ; exit (O) ;

} // i f - f inding-out (mgi , f p) ; dimx = mgi.Wndw.xlr - mgi.Wndw.xu1; mascarada (MASK) ; mapa = (BYTE *) malloc (mgi .Bytespl * (mgi .Wndw .ylr + 1)) ; texto = (BYTE *) malloc(mgi .Bytespl * (mgi .Wndw. ylr + 1)) ; IniciaGraf icoso ; linsc = mapa; lintxt = texto; int x = 0,y = O; if(mapa && texto) {

while( ! f eof (fp) {

pcx-read-line(linsc,fp,mgi.Bytespl); memset (linsc + dimx/8 , OxFF ,mgi . Bytespl - (dimx/8 -1)

memcpy (lintxt , linsc ,mgi . Bytespl) ; linsc += mgi.Bytesp1; lintxt += mgi.Bytesp1;

1 ;

1 for(y = O, linsc = mapa ;y < mgi.Wndw.ylr; y++, linsc +=

mgi.Bytesp1) despliega(linsc,x,y,mgi.Bytespl,MASK) ;

getch0 ; linsc = mapa; if( strcmp( ans,“S” 1 == O 1

A.4. Funciones de escalamiento y misceláneas 77

{ blockzones(linsc, mgi.Bytesp1, mgi.Wndw.ylr,MASK,O); for(y = O, linsc = mapa ;y < mgi.Wndw.ylr; y++, linsc

+= mgi.Bytesp1) despliega(linsc,x,y,mgi .Bytespl,MASK) ;

getch0 ; 1 CierraGraf icos 0 ; sequencezones (mapa ,mgi . Bytespl , mgi . Wndw . ylr , ROW-MAJOR , zone-count ,MASK, zonas, (

free (mapa) ; pbase = new patbase; rewind (op) ; fwrite (&zone-count ,sizeof(unsigned) , 1 ,op) ;

for(y =O; y < zone-count; y++) if( (pats Cy1 = new patron) ! = NULL )

{ pbase+lx = 50; pbase+ly = 70; pats Cy1 +lx = LNX ; pats Cyl+ly = LNY; trans(pbase,zonas[yl ,MASK,texto,mgi.lBytespl) ; if(pbase+lx > O && pbase+ly > O) {

clrscr O ; despliega (pbase ,O> ; reduce (pbase ,pats [y] ; //despliega(pats[y], 25); for(unsigned yi = O; yi < LNY; yi++)

for(unsigned xi = O; xi < LNX; xi++) fwrite (&pats Cy] +patred Cyi] [xi] ,sizeof(float) , I , op) ;

gotoxy (8,231 ; printf ( ' ' Numero de patron Correspondiente : ' ') ; scanf("i!u",&salida); fwrite(&teachCsalidal COI ,sizeof(floiat) ,lO,op) ;

1 }

78 A. Extruccción de Regiones

} // main ...

// . .

// Funcion : void despliega. // Esta funcion despliega en la pantalla una matriz conteniendo el patron.

void despliega(patbase *phase, unsigned off set) // ~ _ _ ~ ” ~ ~”

{ int i , j ; for (i = O; i < pbase+ly; i++)

for ( j = O ; j < pbase-lx; j++>

{ gotoxy(j + I + o f f s e t , i + l ) ; if( pbase+base [il [jl == I .O

p r i n t f ( “ % c ” , ” ) ; }

1

// Funcion : void reduce(patbase *phase, patron *pat) // Esta funcion reduce un patron de bits de la matriz original y el // resultado se transfiere a una matriz de tamao estandar. . .

void reduce (patbase *pbase , patron *pat) {

unsigned i , j = O, xnew = O, ynew = O;

float r x l = (float) (pbase+lx - 2) / (float)pat+lx; float ryl = (float) (pbase-+ly - 2) / (float)pat+ly;

A.4. Funciones de escalamiento y miscela'neas 79

for ( ynew = O, i = 1; ynew < pat+ly && i < pbase+ly; ynew++ 1

{ if( pew == O 1

else

for( xnew = O, j = 1; xnew < pat+lx && j < pbase+lx;

i = 1 ;

i = redondo( (ynew + 1) * r y l ;

xnew++ 1 {

if( xnew == 0 )

else

if( (pat+patred [ynewl [xnewl = pbase"+base [il [jl) ==

j = 1;

j = redondo( (xnew + 1) * r x l ;

1 .O) {

gotoxy(xnew + 1 + 50,ynew+l); pr int f ("%c",");

1 1

1 ) // Fin de reduce ...

//""""""""""""" // funcion: float radio(float,float) // Devuelve el radio SzNw / SzOr y revisa que no sea cero o infinito.

float radio(float SzOr, float SzNw) //

{ if( SzNw == O )

{

1 {

printf ( ' La razon es i n f i n i t a . . . \n y y ) ; return (O) ;

if( SzOr == 0 )

printf ( I No hay razon. . . y y ) ;

80 A. Extraccción de Regiones

return (0) ;

1 return (SzOr/SzNw) ;

} // Fin de radio ...

// - ""_ // funcion: int redondo(fioat test) // Devuelve el flotante mas cercano+ al redondeo del numero a prueba:test.

unsigned redondo( float tes t // "_ "" ~

{ if( ( ce i l ( tes t ) - test ) <= ( test - f loor(test)

else return (unsigned) cei l ( test) ;

return (unsigned)floor(test) ; 1 // Fin de redondo.

// Funcion : void trans. // Esta funcion reduce un patron de bits del archivo PCX g el resultado se // carga como un patron en una estructura declarada para tal efecto.

void trans(patbase *pbase,ZONE *zona,BYTE *MASK,BYTE *image,int dx)

~~ ~ ~ ""

{ BYTE *wo; // Recorre el perimetro delimitado ... int pos ,posini ,posf in; unsigned x , y , i , j ;

if( image == NULL 1 I zona == NULL) {

printf("Hay algo raro . . . No hay mapa O no hay dims. . . \n' '1 ;

return; 1

A.4. finciones de escalamiento 91 misceláneas 81

if( ((zona+y2 - zona+yl + 1) > pbase+ly ) 1 1 ( zona+sizex > pbase”+ly 1)

{ pr in t f (‘ ‘El patron es muy grande para ser tomado en

ret urn ; } // if zona... f o r ( i = O , y = zona+yl ; y <= zona+y2 ; i++, y++ )

cuenta. .\n’ ’1 ;

for( j=O,x = zona+xl, wo = image + y *dx + x; x <= zona+x2; x++, wo++)

{ if(x == zona+xl) { posini = zona+posi; posfin = O ; } else

if(x == zona+x2)

else { posini = 7 ; posfin = zona+pos2; }

{ posini = 7 ; posfin = O ; } for( pos = posini ; pos >= posfin; pos-- -- )

if(*wo & MASKCpos])

else pbase+base Cil Cj++l = O . O ;

pbase-+base [il [j++l = l . O ; }

pbase+lx = j ; pbase+ly = i;

} // Fin de trans

//

// // Das ist alles ... 93/11/28. Far Away, So Close ...