• No se han encontrado resultados

Práctica 7: Clases en C++ La Clase Clmagen

N/A
N/A
Protected

Academic year: 2022

Share "Práctica 7: Clases en C++ La Clase Clmagen"

Copied!
9
0
0

Texto completo

(1)

Práctica 7: Clases en C++

La Clase Clmagen 0. Instrucciones sobre la entrega de la práctica 7

En esta práctica a entregar por el alumno de forma individual se usará una clase imagen en C++ con el fin de leer imágenes en formato pgm o en formato comprimido rle. El alumno también implementará métodos para guardar las imágenes comprimidas o no, así como otros métodos. Finalmente un menú permitirá ejecutar todos los métodos implementados.

Todos los métodos a implementarse así como el menú vienen descritos en el apartado 3 de este guión. Se proporcionan al alumno los siguientes ficheros:

• practica7.cpp que contendrá el menú y las llamadas a los métodos.

o Fichero a completar por el alumno para la realización de la práctica.

• CImagen.h que contiene la definición de la clase.

o Este fichero no puede ser modificado.

• CImagen.cpp que contendrá el constructor, el destructor, el constructor copia y los diferentes métodos a implementar especificados en la definición de la clase.

o Fichero a completar por el alumno para la realización de la práctica.

Se incluye ya resuelto como ejemplo el constructor.

Se valorará tanto el funcionamiento de cada una de las partes como la claridad del código y los comentarios. El código se evaluará con diferentes imágenes pgm y rle para comprobar su funcionamiento.

La práctica deberá subirse a través del acceso identificado a la tarea correspondiente antes de la fecha límite (23 de mayo). Únicamente deberán entregarse los ficheros practica7.cpp y CImagen.cpp debidamente comentados y con el nombre y DNI del alumno como un comentario en la primera línea de cada fichero. Para la corrección incluiré estos ficheros en el proyecto junto con el fichero original CImagen.h para compilarlo y evaluar su funcionamiento.

(2)

1. Objetivos

El objetivo de esta práctica es introducir al alumno en la programación orientada a objetos en C++. Para ello deberá implementarse una clase en C++ para manejar imágenes digitales. En esta práctica manejaremos imágenes digitales en niveles de gris, como la que se muestra en la figura 1.

Fig. 1

2. Imágenes digitales

Podemos entender una imagen digital como un array bidimensional, en el cual, cada elemento tiene un valor proporcional al brillo de ese punto. Valores cercanos a cero representan elementos oscuros de la imagen, mientras que valores altos representan zonas claras. Cada uno de estos valores se denomina pixel, término anglo-sajon que deriva de Picture Element. El array tendrá un número de columnas y filas determinado (nfil, ncol). Esto lo podemos ver representado en la figura 2.

Fig. 2

ncol

nfil

(3)

2.1. Formatos

Las imágenes digitales se almacenan en un fichero con un formato determinado. Existen una gran cantidad de formatos, cada uno de ellos está más indicado para una aplicación en concreto. En nuestro caso vamos a trabajar con imágenes en formato pgm (Portable Gray Map). A continuación se muestra un ejemplo de una imagen en formato pgm.

P2 24 7 255

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 255 0 7 7 7 7 0 0 11 11 11 11 0 0 15 15 15 15 0 0 3 0 0 0 255 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 15 0 0 3 3 3 0 255 0 7 7 7 0 0 0 11 11 11 0 0 0 15 15 15 15 0 0 3 0 0 0 255 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 0 0 0 3 0 0 0 255 0 7 7 7 7 0 0 11 11 11 11 0 0 15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Fig. 3 El formato del fichero es el siguiente:

P2: Es una cadena de caracteres que identifica el formato pgm.

Número de columnas: A continuación se escribe el número de columnas de la imagen (24).

Número de filas: Separado por un espacio se escribe el número de filas de la imagen (7).

Valor máximo: Separado por un retorno de carro se escribe el valor máximo de cada elemento de la imagen (255, es decir, cada elemento ocupa un byte).

Píxeles: A continuación se escriben separados por espacios cada uno de los pixeles en formato ASCII (1 byte cada uno).

Filas: Las diferentes filas de la imagen están separadas por el carácter ‘\n’. Esto no siempre es así y pueden escribirse de forma continua todos los valores. De hecho así es como se realizará en la práctica para simplificar.

Aunque hay saltos de línea cuando acaba cada línea, estos no son necesarios y los valores pueden almacenarse de forma consecutiva. Puesto que conocemos el número de columnas, es posible conocer los datos que corresponden a cada una.

Junto con la práctica se proporcionan algunas imágenes de prueba. Podemos abrir cada una de ellas utilizando un visor estándar de imágenes. En el siguiente link se encuentra un visor muy versátil: http://www.stratopoint.com/download/11view.exe

El visor visualizará la imagen si ha sido guardada correctamente. Si hay menos valores de los que debería haber según el número de filas y columnas la imagen no se visualizará. Por el contrario si hay más valores, el programa ignorará los sobrantes. Se recomienda abrir las imágenes con el bloc de notas para ver la cabecera y como se han guardado los valores.

(4)

2.2. Compresión de imágenes

El formato que hemos elegido para almacenar la información de la imagen no es demasiado eficiente. Dependiendo del número de filas, de columnas de la imagen, ésta ocupará una cantidad de memoria. El número de bytes que ocupa la imagen lo podemos calcular de la siguiente manera:

Nº de Bytes = nfil·ncol·P

Donde P es el número de bytes que ocupa cada pixel de la imagen (1 byte en nuestro caso). Por ejemplo, si una imagen tiene 500 filas x 500 columnas y cada uno de sus píxeles ocupa 3 bytes, en total tendremos: nº de bytes = 750.000 Bytes = 732 KB.

Este será realmente el espacio que ocupará en memoria. Pero al guardar el fichero, cada valor estará separado por un espacio que ocupará memoria y cada valor entre por ejemplo, 0 y 255, ocupará más según las cifras que tenga. Por tanto la imagen ocupará más.

Podemos pensar en una manera de almacenar la imagen mucho más eficiente, lo que comprimiría la información. La idea fundamental se basa en almacenar el valor de un píxel y, justo después, el número de veces consecutivas que se repite el pixel en la imagen. Por ejemplo, si tenemos esta secuencia de píxeles: 0 0 0 0 50 50 128 128 128 128 128 50 50 50 0 0 0 0. Esta secuencia se sustituye por: 0 4 50 2 128 4 50 3 0 4. Es decir, el 0 se repite 4 veces, el 50 se repite 2 veces… etc. En la figura 4 podemos ver un ejemplo más completo de cómo funciona el método:

Nótese como, en este caso, la imagen ha pasado de ocupar 6x7x1Byte = 42 Bytes a ocupar 20 Bytes. Se debe comentar, por último, que el método es capaz de comprimir la información siempre y cuando existan píxeles consecutivos que se repitan.

Además, los datos guardados se guardan de forma consecutiva sin tener que introducir saltos de línea cada vez que acaba una línea. Puesto que tenemos la información de cuantas filas y columnas tiene la imagen podemos saber cuándo acaba una línea y empieza la siguiente. En la primera línea de un fichero comprimido .rle se indica la cadena P2RLE en vez de P2.

Hay que tener en cuenta que el software 11view no es capaz de leer las imágenes comprimidas rle. Para visualizarlas puede utilizarse el bloc de notas. O pueden descomprimirse de nuevo a formato pgm para visualizarlas.

P2 6 7 255

0 0 0 0 0 0 3 3 3 3 3 3 0 3 10 10 10 10 10 3 3 3 0 0 0 3 0 0 0 0 0 255 255 255 255 255

P2RLE 6 7

255

0 6 3 6 0 1 3 1 10 5 3 3 0 3 3 1 0 5 255 5

Fig. 4

(5)

3. Tareas a realizar

1) Crear y configurar un proyecto en Dev C++ y añadir los tres ficheros proporcionados.

2) La clase definida en C++ se proporciona en el fichero CImagen.h (recordar que este fichero no puede modificarse). Nótese que la clase imagen es únicamente para almacenar imágenes sin comprimir. De esta forma cuando se lea una imagen comprimida deberá descomprimirse antes de guardarla en la clase, y cuando se quiera guardar una imagen comprimida, la acción de comprimir deberá realizarse justo antes de guardarla a partir de los datos almacenados en la clase.

#ifndef __CIMAGEN_H__

#define __CIMAGEN_H__

class CImagen{

private:

unsigned char *imagen; //Elementos de la imagen,

// tratamos la información como un vector

int nfil; //Número de filas de la imagen int ncol; //Número de columnas de la imagen int maxval; //Valor máximo de cada pixel

int imagCargada; // 1 si hay ninguna imagen cargada, 0 en caso contrario

public:

CImagen();

CImagen(CImagen &imag_orig);

~CImagen(void);

//Lee una imagen desde un fichero void LeerFichero(char *nombrefichero);

void LeerFicheroComprimido(char *nombrefichero);

void GuardarFichero(char *nombrefichero);

void GuardarFicheroComprimido(char *nombrefichero);

void Aclarar(int K);

void Oscurecer(int K);

void LiberarImagen();

};

#ifndef __CIMAGEN_CPP__

#else

#endif

#endif

3) Programe los siguientes constructores:

CImagen();

Se proporciona en el fichero CImagen.cpp y se encarga de inicializar las variables a 0 y la el vector imagen donde se almacenarán las imágenes.

CImagen(CImagen &imag_orig);

Constructor copia. Deberá copiar las dimensiones de la imagen así como los datos de ella.

~CImagen(void);

Destructor. Deberá liberar la memoria asignada a la imagen.

(6)

4) Programe los siguientes métodos de la clase CImagen:

LeerFichero(char *nombrefichero);

Este método lee una imagen en formato pgm y lo almacena en la variable miembro imagen. El nombre del fichero se pasará como argumento al método. Por simplicidad, todos los elementos de la imagen se almacenarán en un array unidimensional. Este método deberá realizar el siguiente proceso:

• Deberá comprobar si no hay una imagen cargada previamente (imagCargada) ya que en este caso no deberá cargar la nueva imagen.

• Además, si el fichero no se puede abrir también deberá indicarse.

• A continuación se abrirá el fichero indicado y se leerá la cabecera. Si en la cabecera no pone P2 (que corresponde a una imagen sin comprimir) deberá indicarse y tampoco se leerá la imagen.

Entonces, con la información leída de la cabecera (filas y columas) deberá realizarse la reserva dinámica de memoría de un array unidimensional (imagen).

• Finalmente se leerá la imagen y se indicará en la variable imagCargada con un 1 si todo ha salido correctamente.

LeerFicheroComprimido(char *nombrefichero);

Este método lee los datos de una imagen a partir de un fichero comprimido en formato rle y almacena los datos en la variable miembro imagen. El nombre del fichero se pasará como argumento al método.

El proceso a seguir será el mismo que en LeerFichero pero en la cabecera de ficheros comprimidos deberá poner P2RLE.

Además, puesto que la imagen debe almacenarse descomprimida, los datos leídos deberán descomprimirse antes de almacenarlos.

GuardarFichero(char *nombrefichero);

Este método se encarga de guardar los datos de una imagen en un fichero con formato pgm. El nombre del fichero se pasará como argumento al método. Hay que tener en cuenta que si no hay una imagen cargada deberá indicarse y no se guardará nada.

GuardarFicheroComprimida(char *nombrefichero);

Este método se encarga de guardar los datos de la variable miembro imagen en un fichero comprimido con formato rle. El nombre del fichero se pasará como argumento al método. Hay que tener en cuenta que si no hay una imagen cargada deberá indicarse y no se guardará nada. Puesto que la imagen almacenada en memoria no está comprimida, será necesario comprimirla según se almacene en el fichero. Para ello, se deberá contar el número de elementos de la imagen que se repiten, almacenando consecutivamente en el fichero el valor y el número de veces que se repite.

(7)

Aclarar(int K);

Este método multiplica todos los datos de una imagen por un factor K que se pasará como argumento al método. Recordar que el valor máximo es maxVal, por tanto, cualquier valor resultado que lo sobrepase deberá limitarse a maxVal.

Oscurecer(int K);

Este método divide todos los datos de una imagen por un factor K que se pasará como argumento al método. Recordar que los valores resultado deberán ser enteros y siempre entre 0 y maxVal.

LiberarImagen ();

Este método deberá liberar la memoria de la imagen actual e inicializar todos los valores al igual que el constructor. Esto permitirá, sin cerrar el programa, liberar una imagen para cargar una nueva con la que poder trabajar.

5) Finalmente, se deberá crear en practica7.cpp un menú que nos permita probar todas las funciones. El menú deberá volver a aparecer tras seleccionar cada opción hasta que se seleccione la opción 8 que finaliza el programa. El menú deberá ofrecer las siguientes opciones:

1. Cargar imagen.

2. Cargar imagen comprimida.

3. Guardar imagen.

4. Guardar imagen comprimida.

5. Aclarar 6. Oscurecer 7. Liberar Imagen 8. FIN

A continuación se describen las acciones a realizar en cada opción:

1. Deberá solicitar el nombre del fichero pgm no comprimido (con extensión) imagen a abrir. A continuación ejecutará el método LeerFichero.

2. Deberá solicitar el nombre del fichero rle comprimido (con extensión) imagen a abrir. A continuación ejecutará el método LeerFicheroComprimido.

3. Deberá solicitar el nombre del fichero imagen pgm no comprimido (con extensión) a guardar. A continuación ejecutará el método GuardarFichero.

4. Deberá solicitar el nombre del fichero imagen rle comprimido (con extensión) a guardar. A continuación ejecutará el método GuardarFicheroComprimido.

5. Solicitará al usuario el valor K e invocará al método Aclarar.

6. Solicitará al usuario el valor K e invocará al método Oscurecer.

7. Deberá invocar al método LiberarImagen.

8. Finaliza el programa.

(8)

6) Con la práctica se suministran varios ficheros en formato pgm y rle para usar con la práctica. Además de ver las imágenes pgm con el visor de imágenes indicado anteriormente, se recomienda usar un editor de texto para ver su contenido.

imagen1.pgm imagen2.pgm

SII.pgm

7) Ejemplo de uso de la práctica. La siguiente captura se ha obtenido realizando el siguiente proceso:

a. Selección de opciones 3, 4, 5 y 6. En todas ellas se indica que no hay una imagen cargada.

b. Selección de opción 1. Carga del fichero SII.rle. Se indica que el fichero no corresponde con una imagen descomprimida.

c. Selección de opción 1. Carga del fichero SII.pgm. La imagen se carga correctamente.

d. Selección de opción 2. Se indica que ya hay una imagen cargada.

e. Selección de opción 5. Se aclara la imagen por un factor 2.

f. Selección de opción 4. Se almacena la imagen comprimida en el fichero SIIaclarada.rle.

g. Selección de opción 6. Se oscurece la imagen por un factor 4.

h. Selección de opción 3. Se almacena la imagen no comprimida en el fichero SIIoscurecida.pgm.

(9)

i. Selección de opción 7. Se libera la imagen.

A partir de aquí podría cargarse una nueva imagen y continuar usando opciones.

j. Selección de opción 8. Se sale del programa.

Referencias

Documento similar

If certification of devices under the MDR has not been finalised before expiry of the Directive’s certificate, and where the device does not present an unacceptable risk to health

Where possible, the EU IG and more specifically the data fields and associated business rules present in Chapter 2 –Data elements for the electronic submission of information

The 'On-boarding of users to Substance, Product, Organisation and Referentials (SPOR) data services' document must be considered the reference guidance, as this document includes the

In medicinal products containing more than one manufactured item (e.g., contraceptive having different strengths and fixed dose combination as part of the same medicinal

Products Management Services (PMS) - Implementation of International Organization for Standardization (ISO) standards for the identification of medicinal products (IDMP) in

Products Management Services (PMS) - Implementation of International Organization for Standardization (ISO) standards for the identification of medicinal products (IDMP) in

This section provides guidance with examples on encoding medicinal product packaging information, together with the relationship between Pack Size, Package Item (container)

Package Item (Container) Type : Vial (100000073563) Quantity Operator: equal to (100000000049) Package Item (Container) Quantity : 1 Material : Glass type I (200000003204)