Download Descargar el proyecto PDF - ELAI-UPM

Document related concepts
no text concepts found
Transcript
Desarrollo de aplicación DICOM mediante librerı́as
JDT (Java Dicom Toolkit)
José Ma Onrubia
14 de julio de 2003
Índice general
1. Introducción y objetivos
1
2. Estado de la técnica.
2.1. DICOM (Digital Imaging and Communication in Medicine). .
2.1.1. Proceso distribuido. . . . . . . . . . . . . . . . . . . .
2.1.2. Conceptos generales de DICOM. . . . . . . . . . . . .
2.1.3. Conceptos de red DICOM. . . . . . . . . . . . . . . .
2.1.4. Conectividad (Connectivity) . . . . . . . . . . . . . . .
2.1.5. Estándar DICOM . . . . . . . . . . . . . . . . . . . .
2.2. Instancias SOP de imágenes DICOM (DICOM Image SOP
Instances) . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.1. Modelo de información de las imágenes . . . . . . . .
2.2.2. Instancias imagen SOP (Image SOP Instances) . . . .
2.2.3. Relaciones e indentificación . . . . . . . . . . . . . . .
2.2.4. Clasificación de los datos de imagen . . . . . . . . . .
2.2.5. Extensión de la información . . . . . . . . . . . . . . .
2.2.6. Tipos de imágenes . . . . . . . . . . . . . . . . . . . .
2.2.7. Aplicación de los datos de imágenes . . . . . . . . . .
3
3
3
5
15
22
25
3. Estudio de librerias DCMTK.
3.1. Visión general. . . . . . . . . . . . . . . . . . .
3.1.1. Introducción. . . . . . . . . . . . . . . .
3.1.2. Descripción. . . . . . . . . . . . . . . . .
3.1.3. Estructura de datos DICOM. . . . . . .
3.1.4. Servicios de red DICOM. . . . . . . . .
3.1.5. Intercambio de medios de comunicación.
3.1.6. Estatuto de conformidad. . . . . . . . .
3.1.7. Conclusión. . . . . . . . . . . . . . . . .
3.2. Instalación dcmtk351. . . . . . . . . . . . . . .
3.2.1. Dcmnet. . . . . . . . . . . . . . . . . . .
3.2.2. Dcmjpeg. . . . . . . . . . . . . . . . . .
3.3. DicomScope. . . . . . . . . . . . . . . . . . . .
3.3.1. Instalación. . . . . . . . . . . . . . . . .
51
51
51
52
52
53
53
54
54
55
57
58
58
59
3
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
27
28
32
32
36
42
43
47
4
ÍNDICE GENERAL
3.3.2.
3.3.3.
3.3.4.
3.3.5.
Browser. . . .
Viewer. . . .
Print. . . . .
Process Log.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4. JDT (Java DICOM Toolkit)
4.1. Introducción. . . . . . . . . . . . . . . . . .
4.2. Guia de usuario de JDT. . . . . . . . . . . .
4.2.1. Terminologı́a. . . . . . . . . . . . . .
4.2.2. Conjunto de datos (Datasets). . . .
4.2.3. Depósitos. . . . . . . . . . . . . . . .
4.2.4. Imágenes en JDT. . . . . . . . . . .
4.3. Estructura de JDT(Java DICOM Toolkit). .
4.3.1. Árbol de clases. . . . . . . . . . . . .
4.3.2. Paquetes. . . . . . . . . . . . . . . .
4.3.3. Conclusiones. . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5. Estudio de JAVA.
5.1. Introducción . . . . . . . . . . . . . . . . . . .
5.2. Estudio a través de un ejemplo. . . . . . . . .
5.2.1. Clase Ejemplo1 . . . . . . . . . . . . .
5.2.2. Clase Geometrı́a. . . . . . . . . . . . .
5.2.3. Clase Rectángulo. . . . . . . . . . . .
5.2.4. Clase Circulo. . . . . . . . . . . . . . .
5.2.5. Interface Dibujable . . . . . . . . . . .
5.2.6. Clase RectanguloGrafico. . . . . . . .
5.2.7. Clase CirculoGrafico. . . . . . . . . . .
5.2.8. Clase PanelDibujo. . . . . . . . . . . .
5.2.9. Clase VentanaCerrable. . . . . . . . .
5.3. Nomenclatura habitual en la programación en
5.4. Estructura general de un programa java. . . .
5.4.1. Concepto de Clase. . . . . . . . . . . .
5.4.2. Herencia. . . . . . . . . . . . . . . . .
5.4.3. Concepto de Interface. . . . . . . . . .
5.4.4. Concepto de Package. . . . . . . . . .
5.4.5. La jerarquı́a de clases de Java (API). .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
59
60
61
62
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
65
65
66
66
66
73
75
80
80
81
83
. . .
. . .
. . .
. . .
. . .
. . .
. . .
. . .
. . .
. . .
. . .
java.
. . .
. . .
. . .
. . .
. . .
. . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
85
85
87
87
92
93
94
96
97
99
99
103
105
106
106
107
107
107
108
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
6. Desarrollo de nuestra aplicación mediante JDT, JDK
y JBuilder7.
6.1. Introducción. . . . . . . . . . . . . . . . . . . . . . . . .
6.2. Uso de JBuilder 7.0 . . . . . . . . . . . . . . . . . . . .
6.2.1. Introducción. . . . . . . . . . . . . . . . . . . . .
6.2.2. Instalación de JBuilder. . . . . . . . . . . . . . .
6.2.3. Creación de una aplicación JBuilder. . . . . . . .
1.4.1
109
. . . 109
. . . 110
. . . 110
. . . 110
. . . 110
6.3. Uso de librerı́as JDK 1.4.1 . . . . . . . . . . .
6.3.1. Introducción e instalación. . . . . . . .
6.3.2. Estructura de JDK 1.4.1. . . . . . . .
6.3.3. Configuración de JDK en JBuilder. . .
6.4. Instalación de JDT en JBuilder. . . . . . . .
6.5. Implementación de nuestra aplicación. . . . .
6.5.1. Introducción. . . . . . . . . . . . . . .
6.5.2. Estructura de la GUI. . . . . . . . . .
6.5.3. Panel VisorDicom. . . . . . . . . . . .
6.5.4. Panel Crear DICOM. . . . . . . . . .
6.5.5. Panel Procesamiento. . . . . . . . . . .
6.5.6. Panel Cliente/Servidor. . . . . . . . .
6.6. Distribución de la aplicación. . . . . . . . . .
6.6.1. Generación del archivo ejecutable java.
6.6.2. Ejecución del archivo ejecutable java.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
132
132
133
138
139
142
142
143
144
158
168
172
173
173
175
A. ESTÁNDAR DICOM PARTE 1
177
A.1. Introducción. . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
A.2. Alcance y campo de aplicación. . . . . . . . . . . . . . . . . . 180
A.3. Definiciones. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
A.4. Sı́mbolos y abreviaturas. . . . . . . . . . . . . . . . . . . . . . 182
A.5. Objetivos del estándar DICOM. . . . . . . . . . . . . . . . . . 183
A.6. Contenido del estándar DICOM. . . . . . . . . . . . . . . . . 184
A.6.1. Estructura del documento. . . . . . . . . . . . . . . . 184
A.6.2. PS 3.2: Conformidad . . . . . . . . . . . . . . . . . . . 184
A.6.3. PS 3.3: Definiciones de objetos de la información
(IOD´s) . . . . . . . . . . . . . . . . . . . . . . . . . . 186
A.6.4. PS 3.4: Especificaciones de las clases de servicio. . . . 188
A.6.5. PS 3.5: Estructura de datos y semántica . . . . . . . . 188
A.6.6. PS 3.6: Diccionario de datos . . . . . . . . . . . . . . . 189
A.6.7. PS 3.7: Intercambio de mensajes. . . . . . . . . . . . . 189
A.6.8. PS 3.8: Apoyo de comunicación de red para el intercambio de mensaje . . . . . . . . . . . . . . . . . . . . 190
A.6.9. PS 3.9: Soporte de comunicación para el intercambio
de mensajes punto por punto. . . . . . . . . . . . . . . 191
A.7. Relaciones entre las partes del estándar. . . . . . . . . . . . . 193
6
ÍNDICE GENERAL
Capı́tulo 1
Introducción y objetivos
Dicom (Digital Imaging and Communications in Medicine) es el estándar
industrial para transferencia de imágenes digitales e información médica
entre computadoras. Dicom permite la comunicación digital entre equipos
de diagnóstico, terapéuticos y entre sistemas de diferentes fabricantes.
Se ve entonces, la gran importancia de este estándar, ya que da la
posibilidad de interconectar sistemas informáticos de diferentes fabricantes
y hace posible que se comuniquen entre sı́, lo que en un hospital, donde los
aparatos médicos son de muchas marcas diferentes, debido a la especialización, es tremendamente interesante y necesario.
La estandarización de archivos médicos hace posible que, mediante una
transmisión segura, los datos de los pacientes puedan viajar de departamento en departamento, de hospital en hospital, lo que hace que esa
información pueda ser vista remotamente de la zona de adquisición de
las imágenes. Esto permite que los médicos puedan diagnosticar desde su
casa, buscar diferentes opiniones de otros médicos expertos de una forma
sencilla y rápida, un orden y estructura de los datos más efectivo y seguro,
y muchos otros tipos de ventajas.
Objetivos
Los objetivos de este estándar son:
lograr una interfaz común para todos los dispositivos de imágenes (tomografı́a, resonancia magnética, ultrasonido, rayos x, etc).
intentar desligar Dicom de las instituciones que lo desarrollan para que
realmente pueda ser un estándar independiente.
debe ser aplicable a toda la esfera de las imágenes médicas, desde su
1
CAPÍTULO 1. INTRODUCCIÓN Y OBJETIVOS
José Ma Onrubia
transmisión hasta el tratamiento e impresión.
De momento Dicom facilita, pero no garantiza, por si mismo que se
cumplan todos los objetivos que se intentan lograr en los sistemas de gestión
de imágenes.
Debido a todas estas ventajas y posibilidades para que los hospitales y
la medicina en general funcione mejor, es de gran interés avanzar por estas
lı́neas de trabajo. Por esto lo interesante de avanzar por este camino.
La creciente utilización de sistemas de adquisición y tratamiento digital
de imágenes médicas ha hecho necesaria la adopción de estándares que
posibiliten el intercambio de éstas tanto dentro de las propias instituciones
como fuera de ellas.
El estándar DICOM 3.0 nace en el año 1993, a partir de un rediseño
completo de la publicación normalizada No 300-1988 de ACR-NEMA y
pertenece al campo de la Informática Médica por lo que, en principio, esta
norma se solapa con otras de este campo.
El avance de la estandarización poco a poco va adquiriendo todo su
significado:
Se homogeneizan los estándares de codificación de la información y
del conjunto de datos resultantes de utilizar los Objetos de información (imágenes) con las Clases de Servicio (impresión, almacenamiento,
etc), ası́ como se especifican varias técnicas de compresión normalizadas (JPEG con y sin perdidas).
Se muestran las reglas de codificación que se deben cumplir para construir un secuencia de datos para ser transmitida como un mensaje.
Se especifica los servicios de comunicaciones y los protocolos necesarios
para, en un entorno de red, intercambiar mensajes.
Se define la utilización de un conjunto de protocolos OSI (Interconexión de Sistemas Abiertos) para asegurar una comunicación eficiente y que soporte una amplia variedad de tecnologı́as de red basadas
en normas internacionales como la ISO 8802-3 CSMA/CD (la famosa
red Ethernet), ATM (muy en boga actualmente), X.25, etc. Y como
protocolo de transporte se puede utilizar el famoso TCP/IP que hay
que recordar que es un protocolo de propósito general, por lo que el
sistema, en este apartado, es realmente abierto y compatible con la
mayorı́a de las redes que se están instalando actualmente en los centros sanitarios.
2
r
GVA-ELAI-UPMPFC0074-03
Capı́tulo 2
Estado de la técnica.
2.1.
DICOM (Digital Imaging and Communication in Medicine).
En esta sección se van a explicar un número de conceptos definidos por el
estándar de DICOM. Primero se describe como punto de partida el modelo
de un proceso distribuido, a partir del cual vamos a introducirnos en los
conceptos DICOM. Se explican las partes que tratan con la información
(Clases de Servicio) y otras cuestiones.
En las dos siguientes subsecciones se describen el intercambio a través de
la red de la información.
Finalmente, se dan las caracterı́sticas que aseguran la conectividad y una
descripción de las partes del estándar.
2.1.1.
Proceso distribuido.
Un simple modelo de un proceso distribuido (figura 2.1) servirá para
explicar el mecanismo y terminologı́a usada en el estándar DICOM.
Un proceso distribuido está formado al menos por dos procesos que comparten información y confı́an el uno en el otro. Varios procesos distribuidos
actuando juntos proporcionan servicios para sistemas en entornos como
departamentos de radiologı́a.
3
CAPÍTULO 2. ESTADO DE LA TÉCNICA.
José Ma Onrubia
Figura 2.1: Proceso distribuido
Antes de que los procesos puedan actuar juntos, una serie de temas tienen
que ser tratados. Tienen que estar de acuerdo en la información que se va
ha intercambiar y seleccionar las operaciones que cada parte realizará:
El papel de cada parte debe ser definido como cliente o como servidor.
La parte que utiliza la operatividad de la otra, tienen el papel de
cliente. La parte contraria actuando sobre un modelo tiene el papel
de servidor. El funcionamiento de ambas partes viene definida por
la relación que comparten. La relación define que parte y bajo que
condición toma la iniciativa en el proceso. En muchos casos los clientes
provocan el proceso, pero a veces lo hace el servidor.
Además de los papeles que desempeñan, ambas partes tienen que estar
de acuerdo en la información que van a intercambian. La información
está definida por el contexto del servicio que el proceso distribuido
está realizando.
La operación define como debe ser procesada la información intercambiada en la otra parte, tal como almacenar información, devolver un
resultado, etc.
La combinación del contexto, relación, operaciones e información es la
piedra fundamental del procesamiento distribuido y tiene que definirse antes
de que una aplicación se realice (un intercambio). Todos estas cuestiones
son parte del dominio de la aplicación (application domain) de los procesos
distribuidos. Estos no se ocupan de la forma en que la información se
intercambia, pero cuentan con los servicios de menor nivel (p.e. TCP/IP)
suministrados por el dominio del intercambio (exchange domain) para
4
r
GVA-ELAI-UPMPFC0074-03
2.1. DICOM (DIGITAL IMAGING AND COMMUNICATION IN
José Ma Onrubia
MEDICINE).
poder hacer frente al proceso de comunicación.
Ambas partes, cliente y servidor, tienen que ser capaces de emitir peticiones a los servicios de menor nivel. Los servicios de menor nivel llevarán el
intercambio y estarán ocultos para el dominio de la aplicación del cliente o
servidor. La parte que solicita los servicios es el usuario del servicio (service
user ). El equivalente es el proveedor del servicio (service provider ). Ambas
partes pueden tener distintas implementaciones, pero comparten el mismo
conocimiento sobre como se intercambian los datos (protocolo) y tienen el
mismo interface lógico (formato de petición) entre sı́.
Ambas partes deben determinar cómo viene representada la información
en el formato de bit/byte. El proveedor del servicio debe determinar en
qué formato la información fue transferida y convertida a la representación
esperada por el dominio de la aplicación. La representación es conocida
entre el usuario y el proveedor del servicio en cada parte. Después del intercambio, la información presentada a los procesos utilizando la información
es igual en ambas partes, independientemente de como fuera intercambiada.
El intercambio fı́sico entre los proveedores del servicio puede ser vı́a
network o media. Cada mecanismo tiene su propia forma de manejar el
conocimiento de la representación.
2.1.2.
Conceptos generales de DICOM.
DICOM es un estándar que cubre en parte las cuestiones planteadas en la
sección anterior. Esta sección abordará los conceptos generales con respecto
al mecanismo de intercambio actualmente usado. DICOM utiliza su propia
terminologı́a para describir el contexto, relaciones, etc. El primer paso es el
mismo modelo que para el procesamiento distribuido con la transformación
de la figura anterior en la misma figura aplicando los términos equivalentes
de DICOM.
Clases de Servicio (Service Classes) y Clases SOP (SOP Classes).
La relación entre ambas partes se define por la descripción de la Clase de
Servicio. La Clase de Servicio describe explı́citamente los papeles que ambas
partes desempeñan. Con DICOM ambos papeles son llamados: Usuario de
la Clase de Servicio o SCU (Service Class User ) (cliente) y Proveedor de la
Clase de Servicio o SCP (Service Class Provider ) (servidor). No hay que
confundir SCU y SCP con el usuario del servicio y el proveedor del servicio
del dominio del intercambio.
r
GVA-ELAI-UPMPFC0074-03
5
CAPÍTULO 2. ESTADO DE LA TÉCNICA.
José Ma Onrubia
Figura 2.2: Modelo de un proceso distribuido
Parte de la Clase de Servicio es la descripción de la información y
operaciones. En DICOM estas están combinadas con la definición de la
clase, llamada Clase de Servicio de Par Objeto (Service Object Pair Class)
o Clase SOP (SOP Class). En cada definición de Clase SOP una única
definición de Objeto de información (Information Object Definition) o IOD
es combinado con uno o más servicios. Para cada uno de estos servicios
los detalles de los papeles de ambas partes que tienen que desempeñar son
invariables. Más de una Clase SOP puede existir en una Clase de Servicio
cuando más de un IOD está implicado.
Una Clase de Servicio entiende la relación de información definida en diferentes IODs. Una Clase SOP identifica las capacidades del proceso distribuido
especı́fico de una Clase de Servicio. Cuando las partes están de acuerdo en
utilizar una Clase SOP, ambas partes deben asegurar que desempeñarán sus
papeles como se describen, utilizando el contexto de la Clase de Servicio
incluida. Antes de que la información se intercambie puede tener lugar la
identificación de la Clase SOP, que es una parte importante que tiene que
6
r
GVA-ELAI-UPMPFC0074-03
2.1. DICOM (DIGITAL IMAGING AND COMMUNICATION IN
José Ma Onrubia
MEDICINE).
realizarse al principio. El mecanismo usado depende del tipo de intercambio:
network o media.
Utilizando la Clase de Servicio y otras definiciones derivadas, las partes
en el entorno de un proceso distribuido funcionan juntas mediante los
servicios proporcionados por el dominio del intercambio.
Figura 2.3: Clases de servicio DICOM
Definiciones de Objeto de Información (Information Objects Definitions).
La parte de información de una Clase SOP es definida en los IODs. Un
IOD es una colección de partes de información relacionada, agrupadas en
Entidades de información (Information Entities). Cada entidad contiene
información sobre un único objeto (mundo real) como un paciente, una
imagen, etc. Dependiendo del contexto definido por la Clase de Servicio, un
IOD consiste en una entidad de información única llamada IOD normalizado
(normalized IOD) o una combinación de entidades de información llamada
IOD compuesto (composite IOD). Las Clases de Servicio que llevan a cabo
r
GVA-ELAI-UPMPFC0074-03
7
CAPÍTULO 2. ESTADO DE LA TÉCNICA.
José Ma Onrubia
funciones de administración (en su mayor parte cuestiones simples) utilizan
IODs normalizados, aquellas que manejan el flujo de imágenes (estructura
compleja de información) utilizan IODs compuestos. La relación entre
diferentes entidades de información (estructuración) y los IODs compuestos
se describe en el modelo de información (información model ) perteneciente
a la Clase de Servicio. Con IODs normalizados (solo una entidad de
información) no hay ninguna necesidad de estructuración. Las relaciones en
otras piezas de información están hechas aludiendo a esa información.
Las entidades de información consisten en atributos, describiendo una
única parte de información, por ejemplo, el nombre de un paciente. Los
atributos que tienen una relación están agrupados en módulos de información de objetos o IOMs (Information Object Modules). Los IOMs están
definidos de tal manera que pueden ser usados en más de un IOD. Estos
IOMs también tienen la ventaja de que las descripciones semánticas de los
atributos descritos pueden ser agrupados juntos.
La figura que se ve a continuación representa una visión general de estas
relaciones.
Figura 2.4: Relaciones entre IODs y atributos
Un ejemplo de una IOD compuesto, imagen IOD está representada
siguiente:
8
r
GVA-ELAI-UPMPFC0074-03
2.1. DICOM (DIGITAL IMAGING AND COMMUNICATION IN
José Ma Onrubia
MEDICINE).
Figura 2.5: Ejemplo de una imagen IOD compuesta.
Atributos.
Los atributos son la entidad de información básica y tienen que ser
descritos en detalle. De un atributo, se definen las siguientes caracterı́sticas
en el estándar DICOM:
un único Nombre de Atributo (Attribute Name) (legible por el ser
humano).
una única Etiqueta de Atributo (Attribute Tag) (legible por los sistemas de información).
una descripción de Atributo (Attribute Description) (semántica).
r
GVA-ELAI-UPMPFC0074-03
9
CAPÍTULO 2. ESTADO DE LA TÉCNICA.
José Ma Onrubia
un Valor Representativo (Value Representation) (sintaxis).
un Valor de Multiplicidad (Value Multiplicity).
tipo de clasificación: 1, 1C, 2, 2C o 3 (usadas dependiendo del contexto
de las Clases SOP, Clases de Servicio, papel que desempeña, etc.).
El tipo de clase especifica el uso de los atributos especificados en las
Clases SOP y SCU o el papel del SCP. Dependiendo de la situación, a cada
atributo se le fuerza a tener un valor (tipo 1 ) o a que exista con o sin valor
(tipo 2 ) o que sea opcional que aparezca ese atributo (tipo 3 ).
Dentro de un IOD, los atributos agrupados o individuales pueden ser
condicionados por la situación en la que el IOD está siendo usado. Por
ejemplo, un análisis utilizando contraste puede almacenar información
en un ”modulo de Contrast/Bolus”. Los atributos de este módulo están
por consiguiente disponibles o no disponibles, dependiendo del uso del
contraste. Si se usa, el tipo de clase especificada para los atributos debe ser
obedecida (definida como tipo 1C y tipo 2C).
Elementos de Servicio (Service Elements).
Los Elementos de Servicio son las operaciones permitidas en los Objetos
de información para una Clase SOP definida. El grupo de elementos de
servicio pertenece a la Clase SOP y es llamada Grupo de Servicio (Service
Group).
El Grupo de Servicio de una Clase SOP se selecciona de una lista fija de
Elementos de Servicio de DICOM. Algunos Elementos de Servicio están
proyectados para usarse con IODs compuestos, otros para uso con IODs
normalizados. Una tercera categorı́a, medios de almacenamiento (storage
media) relacionados con Elementos de Servicio, manejando instancias de
Clases SOP normalizadas o compuestas como archivos.
El contexto descrito por la Clase de Servicio está limitado cuando
se utilizan IODs compuestos (p.e., transferir imagen). Elementos de
Servicio semejantes tienen un significado complejo, p.e., STORE, FIND,
MOVE. No hay ninguna relación asumida entre los Elementos de Servicio
individuales en una secuencia cuando se utilizan Clases de Servicio compuestos. Si existe una relación, es fuera del alcance de la Clase de Servicio y
deberı́a estar definida en el proceso fluyente utilizando las Clases de Servicio.
En contraste, las Clases de Servicio utilizando IODs normalizados tienen
un contexto más amplio, como funciones directivas. Estas utilizan los
10
r
GVA-ELAI-UPMPFC0074-03
2.1. DICOM (DIGITAL IMAGING AND COMMUNICATION IN
José Ma Onrubia
MEDICINE).
Elementos de Servicio primitivos para operaciones con piezas sencillas de
información: GET, SET, ACTION, etc. La Clase de Servicio define la
relación de la secuencia de la peticiones primitivas. Con Clases de Servicio
normalizadas ambas partes están al tanto del procedimiento de ambas
partes, utilizando los Elementos de Servicio para controlarlos.
Cada Clase SOP utiliza uno o más Elementos de Servicio de cada uno de
los grupos compuestos (C-XXXX) o de los grupos normalizados (N-XXXX).
Los siguientes Elementos de Servicio están disponibles: C-STORE, C-FIND,
C-MOVE, C-GET, CCANCEL, C-ECHO, N-GET, N-SET, N-ACTION,
N-CREATE, N-DELETE y NEVENT- REPORT. Las semánticas de los
Elementos de Servicio dependen de la Clase de Servicio y de la Clase SOP
en la cual están utilizados.
Los Elementos de Servicio relacionados con Media, M-WRITE, M-READ,
MDELETE, M-INQUIRE-FILE-SET y M-INQUIRE-FILE definen funciones primitivas para el tratamiento con archivos.
Instancias SOP (SOP Instances).
El esqueleto de las definiciones citadas anteriormente toma forma cuando
se utilizan en un proceso distribuido. Después del acuerdo que mantienen
las Clases SOP (implı́citamente la Clase de Servicio), y como los papeles
de la SCU y la SCP están divididos, las instancias de la clase SOP
pueden ser distribuidas entre las dos partes. Los atributos tienen que ser
proporcionados con los valores correctos y almacenado en la Instancia SOP
como se especifica en la definición de los atributos.
Después de recopilar la información, esta será codificada a los formatos
definidos por DICOM, utilizando la representación del la Etiqueta (Tag)
y del Valor (Value) para crear un DICOM data set, en el cual cada
atributo es codificado en un data element. Este data set es manejado por
el proveedor del servicio de intercambio, el cual garantiza que la parte
contraria recibe idéntico data set. Las diferencias en la representación del
sistema especificado son tomadas en una cuenta durante el intercambio,
asegurando que los significados semánticos permanecen intactos.
El receptor del data set decodificará este para extraer la información que
necesita y actuar como acuerdo de la semántica de la Clase SOP.
r
GVA-ELAI-UPMPFC0074-03
11
CAPÍTULO 2. ESTADO DE LA TÉCNICA.
José Ma Onrubia
Identificación.
Como parte del proceso de creación de una Instancia SOP, una identificación es generada como atributo de la SOP Instance. La identificación se
pretende para la utilización por los sistemas de información antes que por
los humanos y tiene dos caracterı́sticas: la identificación de la clase (class
identification) y la identificación de la instancia (instance identification).
Esta identificación tiene que ser usada en un entorno de muchos vendedores en distintas partes del mundo. Para asegurar la unicidad de cada
identificación en todo el mundo, se utiliza un mecanismo para generar
una cadena de caracteres, llamada Identificador Único o UID (Unique
Identifier), tal y como sigue:
root >.<suffix
<
>
La parte de root es proporcionada por una autoridad que garantice que
nadie más utilizará este root. Este número será asignado por estándares de
organizaciones y compañı́as tales como Philips u hospitales, que deberán
asegurar que permanece único a lo largo de sus propios sistemas. Utilizando
un sistema de identificación único, cada sistema tendrá un único root a lo
largo de todo el mundo. El suffix tiene que ser creado dinámicamente por
el sistema en la creación de la instancia.
Un vez que una instance es identificada por un UID, esta debe ser
utilizada consistentemente.
Si se crean copias o la instancia se reproduce sin ninguna modificación,
deberá tener el mismo UID, de lo contrario dos piezas de idéntica información coexistirı́an con diferentes identificaciones, lo que podrı́a conducir a
confusión.
Relaciones.
Además de la identificación de la Clase SOP y la Instancia SOP, los UIDs
también se utilizan para identificar una relación entre instancias. En una
instancia compuesta (composite instance) que contiene una única imagen
perteneciente a una secuencia de imágenes, la Entidad de información (Information Entity) que contiene la información de las secuencias será común
para todas aquellas instancias. En este caso solo se requiere un UID, el
atributo por sı́ mismo identifica qué tipo de entidad de información es
identificada.
12
r
GVA-ELAI-UPMPFC0074-03
2.1. DICOM (DIGITAL IMAGING AND COMMUNICATION IN
José Ma Onrubia
MEDICINE).
En el caso de instancias normalizadas (normalized instances), sólo son
posibles referencias a instancias fuera de sı́ mismas; aquı́ se requiere la
combinación de una identificación de una clase y una instancia.
Con el método de la unicidad de identificación de información utilizando
UIDs, es tan sólo posible comparar si las instancias son iguales. El valor del
UID no tiene ningún significado, y no puede ser utilizado para clasificar,
etc. Utilizando otro método como los atributos más significativos tales
como la fecha y la hora y los números de la secuencia, se puede establecer
la relación entre la información.
Valor representativo (Value Representation).
Para cada atributo se define un Representación del Valor (VR). Una
valor representativo describe como un atributo se codifica en un elemento
de datos. El conocimiento de la valor representativo se comparte por las
partes en el intercambio de información , el proceso de codificación y
decodificación tiene que tener cuidado en la selección del VR correcto para
un atributo (identificado por su etiqueta).
Son posibles dos formas de compartir esta información: compartir un
diccionario de datos que contiene todos los posibles atributos de intercambio, o incluyendo el valor representativo como una parte del data element.
El último método incrementa los gastos de intercambio de información,
pero es mucho más flexible comparado con el uso de un diccionario de
datos compartido. Especialmente en un entorno de muchos proveedores,
sincronizar el diccionario de datos es difı́cil.
Cuando el valor representativo se incluye, el mensaje se codifica con un
VR explı́cito (explicit VR). En el otro caso, la codificación tiene lugar con
un VR implı́cito implicit VR).
Sintaxis de transferencia (Transfer Syntax ).
Antes de que el conjunto de datos (data set) de una Instancia SOP pueda
ser transferida, la forma en la que el conjunto de datos está codificada en
una secuencia de bytes debe ser fija, mediante un acuerdo cuando se usa
el intercambio por red, o almacenados junto con los datos en un medio de
almacenamiento fı́sico (disquete, CD´s ...).
La forma de codificar se especifica por la Transfer Syntax. Tres caracterı́sticas se tienen que definir en la sintaxis de transferencia:
r
GVA-ELAI-UPMPFC0074-03
13
CAPÍTULO 2. ESTADO DE LA TÉCNICA.
José Ma Onrubia
Se especifica un valor representativo (VR).
El orden de bytes de un número múltiple de bytes (palabras, palabras
largas): little endian o big endian.
En caso de compresión: el formato.
El manejo de la transfer syntax es parte del proveedor del servicio.
Ası́ y todo, ambos procesos tienen que iniciar el escenario para un correcta
”transfer syntax”, aceptable para ambas partes.
Análogamente a una identificación de Clase SOP, una transfer syntax es
identificada por un UID.
Descripción
Mirando la figura 2.6 se puede obtener una visión general del flujo
de codificación y decodificación. Los servicios proporcionados dentro del
Dominio del Intercambio tienen que garantizar que en ambas partes las
Instancias SOP contienen la misma información, independientemente de la
representación y método de transferencia.
El proceso de codificación y decodificación tiene dos etapas: Primero se
transfiere la representación interna en el formato definido por DICOM (Data
Set) donde cada atributo es almacenado conforme al valor representativo
definido para ese atributo. La segunda etapa transfiere el data set en una
corriente de bytes que pueden ser manejados por las capas más bajas. Para
la segunda etapa la ordenación de bytes tiene que ser utilizada de acuerdo
con la Transfer Syntax.
La aplicación que está utilizando la información debe saber el significado
(semántica) de la información dentro del data object.
14
r
GVA-ELAI-UPMPFC0074-03
2.1. DICOM (DIGITAL IMAGING AND COMMUNICATION IN
José Ma Onrubia
MEDICINE).
Figura 2.6: Descripción de la codificación y decodificación de las instancias
SOP.
2.1.3.
Conceptos de red DICOM.
En la anterior sección se han discutido los conceptos de DICOM del
dominio de la aplicación. Cuando se utiliza un mecanismo de red para
el intercambio de información, el dominio del intercambio debe contener
r
GVA-ELAI-UPMPFC0074-03
15
CAPÍTULO 2. ESTADO DE LA TÉCNICA.
José Ma Onrubia
funciones requeridas para la comunicación: el dominio de la comunicación.
Figura 2.7: DICOM con intercambio en red.
Entidad de la aplicación (Application Entity ).
Una cuestión importante en las aplicaciones distribuidas en red es cómo
las aplicaciones pueden contactar entre ellas. En DICOM Network, las
partes se reconocen mutuamente mediante las entidades de la aplicación.
Una entidad de la aplicación es aquella parte de un proceso que negocia
con la comunicación. Ella contiene el usuario de servicio del proceso, conteniendo funciones para organizar conexiones y transferencia de información.
Una Entidad de la aplicación tiene un nombre, tı́tulo de la aplicación
(Application Title), que tiene que se utilizado cuando se establece la
comunicación.
16
r
GVA-ELAI-UPMPFC0074-03
2.1. DICOM (DIGITAL IMAGING AND COMMUNICATION IN
José Ma Onrubia
MEDICINE).
Presentación de la dirección (Presentation Address).
Los tı́tulos de la aplicación son nombres simbólicos para los procesos
involucrados en la comunicación. En un sistema de red real, la dirección
de red tiene que ser suministrada. A esto se le llama la Presentation
Address. Se le llama ası́ porque el usuario del servicio es la capa de
aplicación (OSI), el proveedor del servicio, la capa de Presentación (OSI)
(y niveles más bajos). La frontera entre ambos niveles es el punto de
acceso de red donde los datos son transferidos desde la capa de aplicación a
las capas de red. Cada punto de acceso en una red tiene una única dirección.
El mapeo del tı́tulo de la aplicación a la Presentation Address no tiene
que ser único, porque la Presentation Address se utiliza para la iniciación
de la conexión, etc. De cualquier manera, en el nivel de aplicación, el tı́tulo
de la aplicación se usa normalmente para identificar una aplicación como
fuente o destino de información en un directorio o catálogo. Si esto no
puede ser registrado sin ambigüedades la operación de los sistemas puede
llegar a ser un problema.
El formato de la Presentation Address depende del protocolo de red
utilizado.
Los DICOM Networks se realizan en muchos casos utilizando el protocolo
TCP/IP. En este caso la valor representativo se mapea a un TCP/IP
socket. En el caso de un protocolo OSI, debe utilizarse un OSI Presentation
Service Address Point (PSAP) válido.
Negociación de la asociación (Negotiation Association).
La conexión para el intercambio de información entre dos entidades de la
aplicación se llama una asociación (Association). Para una asociación, se
fijan un número de asuntos de comunicación como el contexto en el cual la
información puede tener cambios.
Este contexto, llamado contexto de la aplicación (Application Context),
se define en el estándar DICOM y ambas partes deben estar de acuerdo con
la actuación conforme a la definición del contexto.
Un contexto de la aplicación se define con un UID y durante la iniciación
de una asociación este UID es transferido a las partes. Por comparación del
UID de un contexto de la aplicación, la parte puede decidir si es capaz de
manejar la petición de una asociación. Él aceptará el establecimiento de la
asociación o lo rechazará.
r
GVA-ELAI-UPMPFC0074-03
17
CAPÍTULO 2. ESTADO DE LA TÉCNICA.
José Ma Onrubia
El contexto de la aplicación cubre la operatividad global para el intercambio de información. Qué tipo de información intercambia tendrá lugar a
través de la asociación que está definida por las Clases SOP y las Clases de
Servicio de estas Clases SOP. La parte iniciadora de la asociación propone
a la Clase SOP que será utilizada, el SCU / SCP para cada Clase SOP y la
forma de representación de la información. Dependiendo de las capacidades
de la otra parte, aceptará o rechazará cada Clase SOP individual.
Después de este proceso de negociación, ambas partes conocen mutuamente las capacidades y limitaciones. La auténtica información distribuida
puede tener lugar conforme a las reglas de una Clase de Servicio y una
Clase SOP definidas para estas clases. Cuando una asociación no se requiere
por más tiempo, la asociación se termina.
Contexto de la presentación (Presentation Context)
Para cada Clase SOP negociada durante la iniciación de la asociación
tiene que alcanzarse un acuerdo entre los procesos involucrados acerca de la
transfer syntax usada entre los procesos. La parte iniciadora propone todas
las transfer syntaxes, fijando el contexto de la presentación para esta Clase
SOP. Después de la negociación se establece un Presentation Context para
cada Clase SOP aceptada.
Un Presentation Context se identifica por un número acordado entre las
dos partes. En el contexto de una aplicación puede existir un número de
una Presentation Context. El número de la Presentation Context identifica
la SOP Class para la cual el intercambio de información tiene lugar.
TCP/IP Protocol Stack
La combinación de TCP/IP y una extensión para los servicios de aplicación de OSI es ampliamente usada para implementar DICOM a través de
las redes. Como no hay niveles más altos definidos por TCP/IP, DICOM
define la operatividad de la aplicación, la presentación y sesión de la capa
en el estándar. Esta operatividad se combina en una capa: la DICOM
Upper Layer o DUL.
La DUL utiliza el mismo interface que el protocolo TCP/IP con respecto
del protocolo OSI. En el nivel más bajo de la capa DUL, hay un interface
para el nivel TCP. La asociación DICOM entre las entidades de aplicación
se mapea a una conexión TCP. La presentación de la dirección se mapea a
18
r
GVA-ELAI-UPMPFC0074-03
2.1. DICOM (DIGITAL IMAGING AND COMMUNICATION IN
José Ma Onrubia
MEDICINE).
un número de puerto TCP (TCP port number ), combinado con el número
de IP (IP number ) o nombre del servidor (Host name). Esta combinación del número de puerto TCP y el número de IP se llama dirección
de conexión (Socket Address). En una red esta combinación es siempre única.
Una conexión TCP se define por la combinación de una dirección de
conexión local y una remota. Manteniendo los números de IP únicos de la
red y el número único de puerto en el sistema, cada conexión TCP se identifica únicamente por la combinación. La administración de las conexiones
se hace por un recurso llamado interface de conexión (Socket Interface) que
proporciona funciones para configurar las conexiones, transferir cadenas de
bits, etc.
r
GVA-ELAI-UPMPFC0074-03
19
CAPÍTULO 2. ESTADO DE LA TÉCNICA.
José Ma Onrubia
Figura 2.8: Capas OSI
20
r
GVA-ELAI-UPMPFC0074-03
2.1. DICOM (DIGITAL IMAGING AND COMMUNICATION IN
José Ma Onrubia
MEDICINE).
El puerto TCP de la parte llamada durante la inicialización de la
conexión se debe conocido. Esto puede ser por un acuerdo en el número
de puerto entre las dos aplicaciones, o por un número de puerto, llamado
número de puerto conocido (well known port number ), reservado para las
implementaciones de DICOM (número de puerto 104).
r
GVA-ELAI-UPMPFC0074-03
21
CAPÍTULO 2. ESTADO DE LA TÉCNICA.
José Ma Onrubia
Figura 2.9: Conexión TCP
2.1.4.
Conectividad (Connectivity )
Antes de que las dos implementaciones de DICOM se puedan conectar
entre sı́, se necesita algo de investigación para ver si la conexión es posible.
22
r
GVA-ELAI-UPMPFC0074-03
2.1. DICOM (DIGITAL IMAGING AND COMMUNICATION IN
José Ma Onrubia
MEDICINE).
Esto alcanza desde el bajo nivel de conexión fı́sica hasta la implementación
de la misma Clase de Servicio en el nivel de aplicación.
El acercamiento a una conexión red es diferente comparado con un
intercambio a través de medios de comunicación fı́sicos como CD´s o
disquetes. Durante la negociación de la asociación en un entorno de red,
un número de detalles se pueden establecer todavı́a. En el caso de utilizar
medios fı́sicos no es posible y deberı́a ser dirigido de distinto modo.
DICOM solventa esta cuestión utilizando perfiles de sistema (system profiles) para implementaciones y perfiles de aplicación (application Profiles)
en un entorno de intercambio mediante medios fı́sicos.
Estatuto de conformidad (Conformance Statement).
Un perfil de sistema (System Profile) contiene una lista de las funciones
soportadas y limitaciones o extensiones de estas funciones. Juntos forman un
perfil que se debe ajustar al perfil de la parte que tendrá que cooperar. Estos
perfiles de sistema se describen en un documento que debe ser suministrado
con cada implementación de DICOM: el Conformance Statement(ver figura
2.10).
Figura 2.10: Estatuto de conformidad con perfil del sistema.
En el nivel de aplicación se describen una descripción funcional de la
r
GVA-ELAI-UPMPFC0074-03
23
CAPÍTULO 2. ESTADO DE LA TÉCNICA.
José Ma Onrubia
entidad de la aplicación, las Clases SOP soportadas y el papel que ambos
sistemas desempeñan. Para la implementación de los protocolos de red
puede ser referido a documentación estándar apropiada, con constancia de
las excepciones que restringen el uso en un entorno de red. Las posibilidades
de una conexión fı́sica es también un tema que debe ser dirigido.
Los objetos configurables de una implementación, tales como el tı́tulo de
la aplicación (Application Title), la presentación de la dirección (Presentation Address) de ambas implementaciones y partes, que son mencionadas
juntas con información de como puede ser configurado. Otros objetos
configurables como el tamaño del protocol data unit (PDU) debe ser listado.
Finalmente el soporte para caracteres fija otros, además del estándar
ASCII (tales como extensiones para idiomas Europeos, Japonés, etc)
descrito. Comparando los Conformance Statements se puede verificar si
la conectividad a todos los niveles es posible. Si la implementación de la
información por todas las partes involucradas es igual no se puede asegurar
por verificación con la Conformance Statement.
Dependiendo de cómo de estricta pueda ser interpretada la semántica
de todos los atributos individuales, el nivel de interoperabilidad es más
predecible. Actualmente no hay ningún método para asegurar la interoperabilidad.
Al Conformance Statements pueden añadir más información describiendo en más detalle la información que manejan. Cuando está indicado
qué relaciones están disponibles y que selecciones están hechas por la
implementación comparada con el estándar, éste ayudará a incrementar la
conectividad y la interoperatividad.
Perfiles de aplicación (Application Profiles)
Para ”mediaün perfil de sistema detallado tiene poco sentido porque la
correspondencia no tendrá lugar antes de que se conecten los sistemas, pero
por el momento el médium se lleva a otro sistema. En este caso ambos
sistemas deben garantizar que se ajustan a un formato genérico que habilita
la aplicación que ambos implementan. Este formato genérico se llamo perfil
de la aplicación. Por ejemplo, un sistema que genera datos de imagen en
un medio debe hacerlo conforme a un perfil de aplicación confirmado. Un
sistema utilizando esta imagen puede confiar en este perfil de aplicación
para resultar exitoso.
Dos aspectos son importantes: el formato del medium y la extensión de la
24
r
GVA-ELAI-UPMPFC0074-03
2.1. DICOM (DIGITAL IMAGING AND COMMUNICATION IN
José Ma Onrubia
MEDICINE).
información capturada en el medium. Un perfil de aplicación asegura estos
dos aspectos y proporciona un tipo de etiqueta que puede ser adjuntada al
sistema involucrado y al medium que contiene los datos.
El aspecto fı́sico del medium alude al formato definido en el estándar
DICOM. La parte de información descrita por la Clase SOP es el segundo
aspecto incluido en el Perfil de la aplicación.
Figura 2.11: Estatuto de conformidad con perfil de aplicación
2.1.5.
Estándar DICOM
El estándar DICOM está dividido en varias partes, cada una de ellas
describiendo una cuestión importante tal como las Clases de Servicio, los
IODs, temas relacionados con Network y Media, etc. En la figura 8 se ve
una visión general de la relación entre las diferentes partes.
En este apartado las partes de DICOM son abordadas en el mismo orden
que los temas planteados en los apartados anteriores. Puede ser usada como lı́nea directiva para empezar a leer las varias partes del estándar DICOM.
r
GVA-ELAI-UPMPFC0074-03
25
CAPÍTULO 2. ESTADO DE LA TÉCNICA.
José Ma Onrubia
La parte 1 da una introducción y una visión general del estándar DICOM
y su relación con otros sistemas de información hallados en el entorno
clı́nico. (ver Apéndice A)
Las Clases de Servicio y las Clases SOP incluidas en las Clases de Servicio
están definidas en la parte 4. Para cada Clase de Servicio la operatividad
está delineada siguiendo la descripción de las Clases SOP individuales. Para
cada papel un proceso puede desempeñar los requisitos dados por los dos
con detalles del uso de los atributos si es aplicable. Dependiendo del tipo
de Clase de Servicio (compuesta o normalizada) la descripción es dando un
pequeño contexto o uno detallado. Ası́ mismo los temas que tienen que ser
descritos por cada parte de la Clase SOP en la Conformance Statement son
listados. La parte 4 utiliza los IODs y los Servicios definidos en las Partes
3, 7 y 10.
Figura 2.12: Diferentes partes del estándar DICOM
Los IODs utilizados por las Clases SOP son descritos en la Parte 3.
26
r
GVA-ELAI-UPMPFC0074-03
2.2. INSTANCIAS SOP DE IMÁGENES DICOM (DICOM IMAGE SOP
José Ma Onrubia
INSTANCES)
Empieza con la descripción del IOD completo, dividiéndolo en los grupos
de IODs compuestos y normalizados.
De cada IOD se da una lista de ”Information Object Modules”. La ultima
parte define los atributos individuales agrupados en detalle en los IOMs.
Para los IODs compuestos todos los detalles son listados en esta parte, para
los IODs normalizados el actual uso de los atributos depende del servicio
aplicado y descrito en la parte 4.
En la Parte 5 se describe la codificación de las Instancias SOP en
un conjunto de datos. Se defeinen las reglas para los numerosos valores
representativos (Value Representation) y para las sintaxis de transferencia
(Transfer Syntaxes).
Los Elementos de Servicio utilizados por las Clases SOP se dividen en
dos partes: Parte 7 para los Servicios Network y Parte 10 para los Servicios
Media. En estas partes se definen tanto la codificación del ”network message
headerçomo ”media file header”. El resultado es un mensaje o archivo que
puede ser manejado por el correspondiente mecanismo de intercambio.
Los dos grupos de menor nivel tratan con el intercambio fı́sico de datos.
En la Parte 8 se describen las cuestiones de Protocolo de Red (Network
protocolo), la Parte 9 define la conexión punto-a-punto (point-to-point
conexion) (raramente utilizada) y la Parte 12 define las cuestiones del
formato de Physical Media.
Todos los atributos y UIDs definidos por las varias partes del estándar
DICOM son listadas en el Diccionario de Datos (Data Dictionary) (Parte 6).
El Estatuto de Conformidad se describen en la Parte 2 incluyendo la
manera en que un Conformance Statement se tiene que configurar. Los
Perfiles de aplicación utilizados para el intercambio Media se discuten en la
Parte 12 junto con la .Application Profile layout”.
2.2.
Instancias SOP de imágenes DICOM (DICOM Image SOP Instances)
En el capı́tulo precedente, se han explicado los conceptos DICOM sin
describir en detalle cómo se capturan las imágenes dentro de una instancia
SOP. En este capı́tulo se ve con más profundidad cómo se estructura la
información. Se explicará la diferencia entre los distintos tipos de imágenes,
junto a la forma en que el proceso de creación crea los datos de la imagen.
r
GVA-ELAI-UPMPFC0074-03
27
CAPÍTULO 2. ESTADO DE LA TÉCNICA.
José Ma Onrubia
Final mente, se ve qué manera es la adecuada de usar la información creada
por un sistema.
Las clases SOP DICOM contienen una definición de objeto (IOD) y
servicios para ser aplicados a ese objeto. En la mayorı́a de las secciones que
se ven, sólo se discute la definición del objeto. En el manejo de los datos de
las imágenes, como lo descrito en DICOM, está sólo limitado por la transferencia (clase de almacenamiento SOP) y por el medio de almacenamiento.
En este capı́tulo, además de usar los términos almacenamiento de clase e
instancia SOP, el término no DICOM, Image SOP Class/Instance, se usa
para referirse al proceso de los datos de la imagen.
DICOM no tiene forma de describir el tipo de manejo de datos de las
imágenes; el nombre de almacenamiento de clase SOP es poco claro y es
confuso si se usa en otros contextos.
2.2.1.
Modelo de información de las imágenes
El manejo electrónico de la información requiere un modelo para representar la forma en que la información estará estructurada. Esta estructura es
necesaria para tener instancias uniformes y para hacer posible la descripción
de las relaciones entre instancias de forma clara. Un modelo de información
de imagen deriva de la forma en que las imágenes se manejan en un
departamento de radiologı́a. Las imágenes recogidas de uno u otro aparato,
son recopiladas en una carpeta perteneciente al paciente correspondiente.
Las imágenes son ordenadas en la carpeta conforme al tipo de examen
realizado (series de imágenes que están relacionadas).
Los usuarios de cada tipo de aparato tienen su propia terminologı́a
para esta ordenación, como escáner, rodaja, etc. Cuando los datos de las
imágenes de diferentes fuentes tienen que ser recogidas en un ambiente
único, debe ser posible ordenar los datos de las imágenes de diferentes
fuentes. Esto es sólo posible cuando los datos están estructurados de
acuerdo al mismo modelo de información.
Mapping Real World Examinations
El modelo de información de imagen DICOM está basado en suposiciones
sobre la forma en que la información de diferentes aparatos están relacionados. Ver figura 2.13. Los cuatro niveles de este modelo de información son
paciente, estudio, serie e imagen.
28
r
GVA-ELAI-UPMPFC0074-03
2.2. INSTANCIAS SOP DE IMÁGENES DICOM (DICOM IMAGE SOP
José Ma Onrubia
INSTANCES)
Nivel de paciente
El nivel del paciente contiene la identificación y la información demográfica de éste al cual el estudio le pertenece. Debido a que puede existir más
de un estudio, el nivel del paciente es el nivel más alto (cuando toda la
información es recogida para un solo paciente se lleva a una cuenta).
Sin embargo, es de práctica normal usar el nivel del estudio para recoger
la información manejada por varios sistemas para un única respuesta a este
estudio.
Figura 2.13: Del mundo real al modelo de información
Nivel de estudio
El nivel de estudio es el nivel más importante en el modelo de información. Un estudio es el resultado de una contestación a un cierto
tipo de examen médico. Todas las actividades en un departamento de
radiologı́a se centran en el manejo correcto del estudio. En un estudio,
la información de identificación se guarda y puede contener referencias
a información relacionada al mismo estudio en un sistema de administración.
En general, una respuesta puede envolver procedimientos de diferentes
máquinas. Esto da a lugar a una serie de una o más imágenes, dependiendo
del protocolo definido por el examen realizado. Todos los datos son recogidos
juntos en el mismo estudio principal. Un paciente puede tener muchos
estudios como resultado de otros realizados anteriormente.
r
GVA-ELAI-UPMPFC0074-03
29
CAPÍTULO 2. ESTADO DE LA TÉCNICA.
José Ma Onrubia
Nivel de serie
Después del nivel de estudio todas las imágenes se recogen. El nivel de
serie identifica el tipo de aparato que crea las imágenes, la fecha y el tiempo
de creación de la serie y los detalles del tipo de examen realizado y del
equipo usado.
Realizar una lista de los términos usados en los diferentes aparatos tiene
que ser cuidadosamente considerado. Puede haber palabras que aparentemente signifiquen lo mismo, pero se usan con diferencias en distintos
contextos. Las series siempre son una colección de imágenes que provienen
de una único aparato. La forma en que las imágenes están agrupadas en
series depende del uso médico que se les va a dar. Cómo las imágenes son
adquiridas por una máquina es menos importante para ésta agrupación.
Sin embargo, varios atributos definirán el tipo de adquisición y se pueden
mostrar en la visualización. En algunos casos la relación entre las imágenes
se define mediante la forma en que la adquisición ha tenido lugar.
Cuando las adquisiciones en una secuencia tienen relación espacial o
temporal, las imágenes resultantes de esta adquisición pueden ser agrupadas
en series. Una serie nueva debe comenzar cuando la relación existente entre
imágenes ya no existe.
Otro criterio para agrupar imágenes puede ser coger los datos de una
única parte del cuerpo hecho durante un estudio completo. Por ejemplo,
cuando un aparato produce un número de imágenes del estómago de un
paciente desde diferentes posiciones y momentos, las imágenes pueden ser
agrupadas en una serie. Algunos sistemas producen más de una imagen al
hacer una adquisición de datos. Por ejemplo, algunos escáneres se hacen con
un sistema CT, las imágenes reconstruidas desde cada escaneamiento son
recogidas en series y tienen relación espacial. El siguiente escaneamiento
estará en una nueva serie, porque en muchos casos el proceso de escanear
se hace desde diferentes posiciones.
También, en una serie, una imagen de referencia puede ser incluida como
una descripción de la posición espacial de las rodajas individuales. Ver
figura. Diferentes reconstrucciones puede ser guardada en diferentes series.
30
r
GVA-ELAI-UPMPFC0074-03
2.2. INSTANCIAS SOP DE IMÁGENES DICOM (DICOM IMAGE SOP
José Ma Onrubia
INSTANCES)
Figura 2.14: Ejemplo de ”mapping”de un CT
Para cada tipo de aparato médico hay reglas definiendo los contenidos
que una serie debe describir. Las reglas usadas por un sistema dado son
parte de un perfil de sistema en el estatuto de conformidad DICOM.
Nivel de imagen
El nivel más bajo del modelo de información es el nivel de imagen. Cada
imagen contiene la información de adquisición y posicionamiento al igual
que los datos propios de la imagen. Dependiendo del tipo de aparato, el
nivel de imagen contiene datos para una sólo imagen, dos imágenes (sistema
de dos planos) o una colección de imágenes cogidas en un corto espacio de
tiempo (multiframe images).
El uso de multiframes images guarda la información duplicada en niveles
más altos, pero es sólo posible cuando la relación entre los marcos (frames)
pueden ser descritos de una sola manera. Por ejemplo, los incrementos en
los movimientos del sistema y del tiempo son iguales para todas los marcos.
Creando un multiframe images es más complejo y gasta más recursos que
r
GVA-ELAI-UPMPFC0074-03
31
CAPÍTULO 2. ESTADO DE LA TÉCNICA.
José Ma Onrubia
creando una imagen única. La relación entre marcos, la capacidad del
aparato y la carga de datos producidos deberı́a ser usada para determinar si
se debe aplicar una serie de imágenes simples o un multi marco de imágenes.
2.2.2.
Instancias imagen SOP (Image SOP Instances)
El modelo de información mostrado en la figura 2.13 es una simplificación
del modelo de información completo de imagen DICOM de la figura 2.14.
Cada bloque en este diagrama representa una entidad de información (ver
IOD‘s) del IOD compuesto. Las relaciones indican los puntos cardinales
para cada relación de la entidad de información usada en una instancia SOP.
Cada instancia de imagen SOP tiene que contener la información estructurada de acuerdo al modelo de información DICOM. Cada instancia
de imagen SOP (simple o multimarco) es una instancia compuesta SOP
que contiene el árbol completo de información del modelo de información.
Todas las imágenes en una serie son de un mismo paciente, estudio y serie;
todas las series son del mismo paciente y estudio, etc. En cada composición,
toda la información relacionada con la imágenes está disponible.
Este formato hace más fácil el intercambio y el manejo (especialmente
el almacenamiento) de la información pero incremente la carga de datos
cuando se transfiere un estudio completo.
En este caso las entidades de información del paciente y del estudio tienen
múltiples instancias en la colección de las instancias SOP. En contraste, las
instancias normalizadas SOP (con entidades de información simples) usan
referencias a otras entidades de información , perteneciendo un protocolo
más eficiente, pero requiriendo un manejo más complejo.
2.2.3.
Relaciones e indentificación
Cuando se recoge un grupo de Image SOP Instances las cuales tienen
relación entre ellas, pero están creadas desde diferentes aparatos, es
importante ser capaz de marcar las entidades de información en diferentes
niveles. Son importantes dos aspectos:
1. Todas las modalidades deben tener un mapa (código) consistente de
cómo pasar de unos datos de imagen a una instancia SOP.
2. Las entidades de información individuales deben contener la identificación suficiente de hacer un correcto marcado de las entidades de
32
r
GVA-ELAI-UPMPFC0074-03
2.2. INSTANCIAS SOP DE IMÁGENES DICOM (DICOM IMAGE SOP
José Ma Onrubia
INSTANCES)
información equivalente en otras instancias SOP.
Figura 2.15: Modelo de información de una imagen compuesta DICOM
Estructura de los datos de las imágenes
El primer aspecto requiere que los datos producidos por los aparatos sea
ordenado en series que tengan una relación como la descrita en la sección
nivel de serie (página 30). En los niveles de serie e imagen, la secuencia de imágenes dentro de una secuencia debe ser identificado en un aparato.
Las entidades de información sobre el nivel de serie deberı́a contener
información perteneciente al estudio y al paciente que debe ser comparable
con la información de otros aparatos. La mayorı́a de esta información
viene de fuentes externas como un sistema de planificación. Puede ser
suministrado al aparato por la interfaz de usuario (del papel) o mediante
una conexión a un sistema de información.
r
GVA-ELAI-UPMPFC0074-03
33
CAPÍTULO 2. ESTADO DE LA TÉCNICA.
José Ma Onrubia
Identificación
Si los datos de imagen tienen que ser almacenados en sistemas los cuales
ordenan los datos examinando el contenido de la información de la entidad,
debe haber un consentimiento y un acuerdo para indentificar la información
de la entidad por todos los sistemas (aparatos, sistemas de almacenamiento,
estaciones de trabajo, etc.) los cuales manejan la información.
Visualizar la información es más amplio que sólo ordenar imágenes.
La identificación es también usada para acceder a los datos desde otros
sistemas de información. Los sistemas de información normalmente usan
claves que no necesitan ser interpretadas por los seres humanos, pero tienen
que ser únicos en el ambiente en el que son usados.
El mecanismo DICOM que se ha definido para estas identificaciones son
los UID´s como se discutió en la sección de Identificación (página 12). Cada
una de las entidades de información en el modelo de información tiene su
propia UID, excepto para la entidad de información del paciente. La forma
en que la información debe ser identificada se define por otros sistemas
de información (fuera del visor DICOM) que tratan con la administración
paciente. En este caso se usa un identificador ID para el paciente.
Identificación del estudio
Como el estudio de un examen médico realizado por un doctor es el
centro de todas las actividades en un departamento de radiologı́a, debe ser
reflejada en todas las piezas de información las cuales están relacionadas
con el examen realizado.
Para DICOM esta información se identifica al nivel de estudio. En la
mayorı́a de los casos el atributo UID de la instancia del estudio (Study
Instance UID) identifica la entidad del estudio de información del estudio
perteneciente al resultado del examen del mundo real.
Cuando este UID se usa de una forma consistente por todos los sistemas
involucrados, no es difı́cil relacionar todas las piezas de información con los
datos de la imagen en la instancia DICOM SOP. Sin embargo, esto requiere
una unión entre todos los sistemas involucrados para transferir la clave del
sistema. UID transfer by human beings is not an acceptable practice due
to length and meaningless content of the UID string, it would be error-prone.
A parte de esta unión (link ), UID´s se tienen que soportar por todos los
otros sistemas, no sólo los sistemas involucrados en el manejo de datos de
34
r
GVA-ELAI-UPMPFC0074-03
2.2. INSTANCIAS SOP DE IMÁGENES DICOM (DICOM IMAGE SOP
José Ma Onrubia
INSTANCES)
imágenes. Un sistema que genera los UID´s del estudio juega un mayor rol
para distribuir el UID a otros sistemas involucrados. Normalmente, esto
deberı́a hacerse por un Sistema de Información Radiológico (RIS) o por
un Sistema de Información de Hospital (HIS), que normalmente puede no
siempre soportar el concepto UID.
Cuando el soporte para el UID de la instancia del estudio no
está disponible, no es posible usar este UID como unión a toda la
otra información. Tiene que ser reemplazada en esos casos por otras claves.
RIS usan actualmente una o más claves para acceder a su información
almacenada, número de registro del estudio, etc. Esas claves se imprimen
en papel que pertenece al estudio. Esta información tiene que ser incluida
en la entidad de información del estudio y usada como reemplazo al UID
del estudio.
Usar el UID del estudio como unión con las partes relacionadas de la
información es un aspecto importante para proporcionar un modelo de
información DICOM consistente, el cual puede ser expandido en otras
partes de la información en un departamento de radiologı́a.
Esta consistencia es muy difı́cil de mantener cuando el UID del estudio
se reemplaza por un RIS o un método especı́fico de identificación.
Otras identificaciones
A parte de las claves del sistema, los usuarios necesitan acceder a la
información y quieren usar identificadores que tengan sentido como el
nombre del paciente, su dı́a de nacimiento, fecha del estudio médico, etc.
Los aparatos médicos tienen que proporcionar una información lo más
consistente posible para permitir una identificación por parte de los
humanos. La información de identificación puede ser proporcionada por
una única fuente cuando una unión entre sistemas es posible.
Por ejemplo, el RIS da el nombre del paciente, su fecha de nacimiento,
etc, como parte de la información para realizar un examen médico. Este
método previene el error de máquina y permite una forma más eficiente de
funcionamiento.
r
GVA-ELAI-UPMPFC0074-03
35
CAPÍTULO 2. ESTADO DE LA TÉCNICA.
2.2.4.
José Ma Onrubia
Clasificación de los datos de imagen
El modelo de información define el modelo jerárquico de las entidades
de información para dejar claro cómo la información dentro de diferentes
instancias SOP pueden ser agrupadas en diferentes niveles. En este sección
la información de la instancia SOP está clasificada de acuerdo a las
funciones que tiene, pero independientemente de su lugar dentro del modelo
de la información. Desde luego, hay una fuerte relación entre el proceso de
modelado y el proceso de creación. La siguiente sección describe la forma
de producir los datos de la imagen.
En la figura 2.16 se muestra una descripción de la clasificación y la
relación con la arquitectura del sistema de un aparato médico. Las diferentes clases son creadas en diferentes momentos en el tiempo cuando se
realiza un examen médico. Cada subsistema añade atributos al resultado
final: la instancia de imagen SOP. La siguiente sección discute las clases de
información con más detalle.
Información del paciente
Esta clase contiene información sobre el paciente al que se le realiza un
estudio. En un departamento de radiologı́a la información del paciente
se sabe por otras fuentes, como sistemas de información o formularios en
papel. Sólo tiene que ser registrado de una manera formal por un número de
atributos como nombre del paciente, ID del paciente, fecha de nacimiento,
etc.
La información en esta clase es estable, excepto por la corrección de
errores de escritura y cambios de nombre en caso de enlaces matrimoniales,
etc. El mantenimiento de esta información se hace por sistemas que actúan
como fuentes para aparatos médicos.
Uno o más atributos son clave para la información en otros sistemas de
información. Otros atributos identifican al paciente como una persona o
dan más detalles sobre su condición. Un número de esos atributos son muy
importantes para el proceso completo de identificación y conexión a otra
información en un departamento de radiologı́a.
Para permitir la identificación del paciente y la revisión de un estudio,
el aparato médico tiene que incluir esos atributos en las instancias SOP
creadas.
Procesos en el hospital también tienen que enfrentarse con el manejo de
36
r
GVA-ELAI-UPMPFC0074-03
2.2. INSTANCIAS SOP DE IMÁGENES DICOM (DICOM IMAGE SOP
José Ma Onrubia
INSTANCES)
la información en casos excepcionales. Por ejemplo, cuando un paciente
desconocido es examinado por emergencia, se deben realizar unos pasos
para permitir que la información sea correctamente identificada cuando se
conoce el nombre del paciente.
r
GVA-ELAI-UPMPFC0074-03
37
CAPÍTULO 2. ESTADO DE LA TÉCNICA.
José Ma Onrubia
Figura 2.16: Clasificación de la información de la imagen
38
r
GVA-ELAI-UPMPFC0074-03
2.2. INSTANCIAS SOP DE IMÁGENES DICOM (DICOM IMAGE SOP
José Ma Onrubia
INSTANCES)
Información del estudio
La información del estudio es una clase con una mezcla de información
fuente. Por un lado, la información será suministrada desde un sistema
como un RIS (Sistema de Información Radiológico) que identifica el
estudio a través de más de un sistema. Por otro lado, el aparato médico
añadirá información sobre el paciente en el momento en que el estudio
se realiza. Información de otros sistemas incluyen una identificación del
estudio. Un UID de una instancia de un estudio es la forma más eficiente
de identificación, pero tiene desventajas (ver página 34). Un atributo
alternativo, llamado número de acceso, puede ser usado en un sistema RIS.
En el caso de que no esté disponible un UID de la instancia del estudio
desde fuera de un aparato médico, éste tiene que generar el UID de forma
que garantice que es el único en el sistema.
Cuando las imágenes de un estudio se copian desde un almacenamiento
local para un destino remoto, es muy importante que se use el mismo UID
de la instancia del estudio. Esto previene la existencia de imágenes con
diferentes identificaciones provinientes un mismo estudio. Tales imágenes
nunca pueden ser recogidas juntas sin la intervención de un operador.
Otra información suministrada al aparato médico son los nombres de
los médicos solicitantes o la lectura de las imágenes y la información del
paciente dinámica como la edad, el peso, la ocupación, etc.
La información incluida localmente por el aparato médico identifica el
estudio proporcionando un valor para el atributo ID del estudio y la fecha
y hora actual del estudio. El ID del estudio es sólo relevante por el aparato
usado para realizar el examen médico.
Información de la serie
La clase de información de serie es la primera que es completamente
generada por el aparato médico. En esta clase el tipo de sistema, la
localización y la identificación del sistema se da. La identificación de las
series consiste de un UID de la instancia de la serie, que únicamente
identifica la serie en los datos de la imagen y una serie en la zona usada
ID que puede ser usado para hacer una secuencia con series en un estudio.
Los ID de las series tienen sólo un significado para el aparato médico en
sı́ mismo, no hay una regla dada para este uso.
Con la información de las series, se suministran más detalles sobre la forma en que las series son realizadas, la gente involucrada, la parte del cuerpo
r
GVA-ELAI-UPMPFC0074-03
39
CAPÍTULO 2. ESTADO DE LA TÉCNICA.
José Ma Onrubia
examinada, etc. La parte de la información del equipo contiene información
general sobre el sistema usado por esta serie. Incluye información sobre la
localización, la identificación del tipo y la serie, cuestiones de calibración,
etc. Estos datos pueden ser compartidos por series pertenecientes al mismo
estudio y realizados mediante el mismo aparato médico.
Se usa un marco de referencia para agrupar imágenes que tienen relación
espacial o temporal. Esto puede ser usado para dividir series en partes o a
través de más de una serie si se aplica la misma relación. Tal relación se
identifica por un UID de marco de referencia compartido entre las imágenes
involucradas.
Información de la aplicación
Los atributos en esta clase dan información sobre la imagen contenida en
la instancia SOP requerida para el diagnóstico y otras aplicaciones. Varios
ejemplos, desde un simple texto añadido como comentario, hasta detalles
como el contraste, terapia y dispositivos usados durante el reconocimiento
médico.
Otro grupo describe la parte del cuerpo examinada usando valores
codificados. Los ajustes del valor de interés (VOI), en la mayorı́a de los
casos llamado anchura de ventana y centro de ventana (window width
y window center), son miembros muy importantes de esta clase. El VOI
es la selección fuera de la gama completa de los valores de pixel que son
clı́nicamente significativos cuando se muestra o se imprime la imagen. Sólo
el rango especificado tiene que ser convertido a nivel de grises disponibles.
La información que dibuja lı́neas o agrega el texto a la imagen mostrada
puede ser en forma del velo matrices que tiene que ser agregado a la
demostración por una estación de inspección, o ya aplicados(aplicado) al
matriz de pixel (quemado en). Sumnistrando la superposición como una
información separada de los datos de imagen, la imagen puede ser mostrada
con o sin la superposición, permitiendo que los datos de imagen puedan ser
usados como entradas para el tratamiento remoto.
Información adquirida
En esta clase de información se guardan los ajustes del equipo de
adquisición. El grado de información depende del tipo de aparato y puede
tener un rango desde unos pocos atributos para un sistema sencillo, a una
estructura compleja. Contiene detalles del sistema de adquisición como los
40
r
GVA-ELAI-UPMPFC0074-03
2.2. INSTANCIAS SOP DE IMÁGENES DICOM (DICOM IMAGE SOP
José Ma Onrubia
INSTANCES)
valores usados de los rayos X por ejemplo.
Las imágenes resultantes de la misma adquisición pueden ser identificadas
con un número de adquisición. Este agrupamiento depende del sistema
y puede ser parte de series sencillas, pero una adquisición sencilla puede
también resultar en múltiples series de imágenes, cada una con diferentes
caracterı́sticas. La adquisición no tiene relación con el modelo de información DICOM y no tiene un identificador UID equivalente.
Información de la posición
Una clase importante es la información dada sobre el posicionamiento de
la imagen dentro del paciente.
Depende del tipo de aparato médico, de la forma en que se describe la
matriz de la imagen posicionada usando términos sencillos como anterior,
posterior, derecha, en frente, etc. Se debe tener cuidado para asegurar que
hay proporcionada información suficiente con la imagen para que no haya
visualizaciones ambiguas (sobre todo en cuestiones de derecha e izquierda).
En una serie que tiene relación espacial, como puede ser imágenes CT
o MR, muchos más detalles se tienen que suministrar sobre la posición
de las imágenes en el espacio tridimensional del cuerpo del paciente. Esta
información permite a sistemas como planificadores de tratamiento de
radioterapia usar el posicionamiento tridimensional para el procesamiento
de los datos de las imágenes.
Otro uso de la información del posicionamiento es para sistemas de
vasculación para describir los movimientos dinámicos.
Información de los datos de las imágenes
Finalmente, los datos de las imágenes provenientes del sistema de
adquisición y procesadas para producir imágenes visibles en formato
digital. Esta clase describe detalles sobre cómo los datos de los pı́xeles
deben ser interpretados, como el tamaño de la matriz de pı́xeles, la valor
representativo de pı́xel y cómo estos están codificados.
Cuando los aparatos médicos son capaces de generar imágenes en
color, tiene que ser suministrada la información sobre cómo los datos son
ordenados en diferentes planos. A parte del formato de la información, esta
clase contiene los datos de los pı́xeles en un marco sencillo, en dos marcos
r
GVA-ELAI-UPMPFC0074-03
41
CAPÍTULO 2. ESTADO DE LA TÉCNICA.
José Ma Onrubia
para sistemas de dos planos o en multimarco. Cuando un multimarco se
genera por un sistema de dos planos es posible almacenar los marcos de los
dos planos juntos. En este caso los marcos de los dos planos se almacenan
alternados (A-B-A-B-...). Para un multimarco las relaciones de tiempo
entre los marcos individuales se describen mediante otros atributos.
La imagen se identifica únicamente por el UID de la imagen. Como
una instancia SOP de una clase de imagen SOP siempre incluye una
porción de la imagen, el UID de la imagen se usa también como UID de
la instancia SOP. Este UID se use para identificar la instancia cuando
se transfiere o se recupera desde un almacen de imágenes o para identificar la entidad de la imagen usándola en un árbol jerárquico de información.
2.2.5.
Extensión de la información
Para el almacenamiento de toda la información descritas en las clases
de arriba se definen atributos que se agrupan en IOD´s (Information
Object Definitions) los cuales dan una descripción genérica de las instancias
SOP para cada tipo de aparato médico. Los atributos que se usan actualmente deben ser descritos en el Estatuto de Conformidad (perfil del sistema).
No siempre es posible guardar toda la información generada por un
aparato en un IOD estándar. En casos el equipo tiene nuevos campos los
cuales necesitan información adicional para alamacenarlos en un nuevo
IOD. Se debe tener cuidado en que las partes que usan esta información
serán capaces de entender esta nueva información. Estos detalles se tienen
que publicar en el Estatuto de Conformidad. Si el uso se acepta, la nueva
información llega a formar parte del estándar.
La extensión puede no influenciar la semántica de la información guardada en los atributos estándares. Tiene que ser un subconjunto apropiado,
compatible con el IOD del que deriva. En otros casos, el equipo de un
vendedor único, puede añadir información para ser usada sólo en la
combinación de sistemas o sólo por el mismo sistema que ha generado los
datos. En esta situación, no existen detalles sobre la información que tiene
que ser publicada en el Estatuto de Conformidad. No hay intención por
otras partes de usar esta información adicional.
Para permitir la extensión de información, DICOM ha definido dos tipos
de atributos: atributos estándar y privados.
Los primeros se usan para codificar los atributos descritos en el estándar
IOD (ver sección .Atributos”página 9). Si no hay extensiones o cambios en
42
r
GVA-ELAI-UPMPFC0074-03
2.2. INSTANCIAS SOP DE IMÁGENES DICOM (DICOM IMAGE SOP
José Ma Onrubia
INSTANCES)
los IOD´s, la clase SOP es una clase SOP estándar.
Los segundos definen atributos o usan atributos estandarizados no
pertenecientes al IOD de una clase SOP especı́fica, no se pude seguir
llamando clase estándar SOP y depende del efecto que cambia a uno de los
siguientes tipos:
Clase SOP extendida: cuando los atributos adicionales no cambian el uso
de la clase SOP. En este caso es un super-conjunto, cuando se usa por
sistemas los cuales no son conscientes de las añadidos, se pueden ignorar
y la imagen puede ser manejada como se dice en la clase SOP estándar.
Una clase SOP extendida usa el mismo UID que la clase SOP estándar. Las
diferencias entre las dos clases se muestra en el Estatuto de Conformidad.
Clase SOP especializada: cuando las adiciones cumplen con el modelo de
información, pero la clase ya no es un super-conjunto. Como consecuencia,
el UID de la clase SOP estándar puede no ser usado; se debe usar un UID
privado para esta clase SOP. Los socios que manejan las instancias SOP
conocen el UID privado y pueden manejar la información. Otros no pueden
aceptar la clase SOP durante la negociación de la asociación o, cuando se
abre un archivo DICOM desde un medio DICOM.
Las Clases SOP privadas no siguen el modelo de información DICOM y
se usan en un contexto completamente privado. Usan mecanismos proporcionados por DICOM para transferir la información. Las clases SOP privadas
usan UID´s privados para prevenir usos incorrectos de la información.
Si una de las tres clases SOP arriba mencionadas se definen con la intención de llegar a ser parte del estándar DICOM, los detalles se publican en
el Estatuto de Conformidad. De otra forma, sólo se usan en un ambiente
cerrado.
2.2.6.
Tipos de imágenes
DICOM define un número de tipos de clases de imágenes SOP, dependiendo del aparato médico que crea la los datos de las imágenes. Cada tipo
tiene su propio IOD para añadir información especı́fica del aparato a la
instancia de la imagen SOP.
Todas las instancias de las imágenes SOP comparten un mı́nimo juego
de información que permite a una aplicación visualizadora manejar las
imágenes independientemente de su tipo.
Una clase de imagen SOP está disponible para encapsular las imágenes
que no están disponibles en el formato digital y sı́ capturadas en formato
de pelı́cula o de vı́deo.
r
GVA-ELAI-UPMPFC0074-03
43
CAPÍTULO 2. ESTADO DE LA TÉCNICA.
José Ma Onrubia
Tipos genéricos de imágenes
Las instancias de las clases de las imágenes SOP tienen un conjunto
básico de atributos; ver figura(2.17). El conjunto mı́nimo de atributos
requeridos para una instancia de imagen SOP consiste en el siguiente grupo
de atributos:
Atributos identificadores: UID de clase SOP, UID de la instancia del
estudio, UID de la instancia de la serie y UID de la instancia de la
imagen (= UID de la instancia SOP).
Tipo de aparato.
Descripción de la matriz de pı́xeles: muestra por pı́xel, filas, columnas.
Interpretación del valor del pı́xel: interpretación fotométrica.
Codificación de los pı́xeles: bits asignados, bits almacenados, bit alto,
representación de pixel, configuración plana.
Matriz de pı́xeles: datos de pı́xel.
44
r
GVA-ELAI-UPMPFC0074-03
2.2. INSTANCIAS SOP DE IMÁGENES DICOM (DICOM IMAGE SOP
José Ma Onrubia
INSTANCES)
Figura 2.17: Juego básico de atributos de las instancias de imagen SOP
Este mı́nimo conjunto permite mostrar los datos de pı́xel y proporciona
la identificación en el nivel de sistema, para el caso de la instancia SOP
para adherirla modelo de la información. Añadiendo más información al
menos para los tres primeros niveles del modelo de información, hace más
entendible a la instancia SOP. Los atributos que identifican la instancia
SOP para seres humanos y permiten que la imagen sea mostrada.
Añadiendo más información para al menos los tres primeros niveles del
modelo de la información, hace la instancia SOP más comprensible. Los
atributos que identifican la instancia SOP para los seres humanos y permiten que la imagen sea visualizada con los correctos ajustes de ventana son:
Nivel de paciente: nombre, ID, dı́a de nacimiento, sexo.
Nivel de estudio: fecha del estudio, hora, nombre del médico, ID del
estudio, número de acceso.
r
GVA-ELAI-UPMPFC0074-03
45
CAPÍTULO 2. ESTADO DE LA TÉCNICA.
José Ma Onrubia
Nivel de serie: número de serie, fabricante, nombre de la institución.
Nivel de imagen: número de imagen, tipo de imagen.
Ajustes de presentación: ancho de ventana, centro de ventana.
Los atributos listados arriba son en la mayorı́a de los casos atributos del
tipo 2 (deben ser suministrados, pero pueden faltar) o del tipo 3 (opcionales).
Tipos de imágenes especiales
El formato genérico descrito arriba se usa en la definición de cada clase
SOP, pero depende del tipo de aparato, esto se extiende con la información
entregada sobre la adquisición, etc. El número de imágenes especializadas
está creciendo por la aparición de nuevas máquinas médicas.
Normalmente, los siguientes aparatos tienen una definición de la clase de
almacenamiento SOP en el estándar DICOM:
Radiografı́a computada IOD, usada por los sistemas radiográficos
tradicionales que trabajan con fósforo que brilla al leerse con sistemas
como PCR.
Tomografı́a computada IOD para escáneres CT. Para este tipo
de aparatos el posicionamiento es importante, para montones de
imágenes, para crear vistas tridimensionales.
Resonancia magnética IOD para sistemas IOD. A parte de la misma
información que para escáneres CT también se da información adicional sobre el protocolo de adquisición.
Medicina nuclear IOD para cámaras usan isótopos radiactivos. Contienen imágenes de especial formato para este tipo de aparatos. Las
imágenes son en multimarco formato.
Ultrasonidos IOD para este tipo de equipos. Estos contienen detalles
sobre la posición y la adquisición de la imagen. Las imágenes pueden
ser en color y se puede usar el multimarco.
Angiografı́a con rayos-X IOD para sistemas digitales cardiológico y
basculares. Este formato puede capturar una cadena en multimarco
o imágenes simples. Inside a run a description of which images are a
mask for image subtraction can be added. Extensive information about
the equipment positioning and acquisition is given to allow the image
data to be processed.
46
r
GVA-ELAI-UPMPFC0074-03
2.2. INSTANCIAS SOP DE IMÁGENES DICOM (DICOM IMAGE SOP
José Ma Onrubia
INSTANCES)
Radiofluoroscopı́a de rayos-X IOD para sistemas como sistemas angiográficos, pero hacer una mesa con columnas en vez de brazos C.
La mayor diferencia es la forma en que se describe la posición de las
piezas del equipo.
Por cada uno de los IOD´s, se describe una lista de módulos en el
estándar DICOM. El uso de unos ciertos módulos a veces dependen de
capacidades o condiciones de ciertos sistemas. Los módulos se seleccionan
o desde un grupo de módulos comunes usados para todos los IOD´s de
almacenamiento SOP, o módulos especı́ficos para sólo un tipo de IOD.
Estos módulos contienen atributos especiales para ese tipo de IOD. Esos
módulos, y a veces atributos individuales, los redefinen y extienden para el
IOD genérico. En la parte PS3.3 del estándar DICOM los IOD, IOM y los
atributos se listan. El anexo A contiene la lista de IOM para cada IOD. En
el anexo C.7 se describen los módulos comunes de los IOD´s, en el anexo
C.8 los módulos especı́ficos de los aparatos médicos. El anexo C.9 mediante
C.12 define un número de módulos que pueden ser añadidos al objeto
imagen, como un módulo más, un valor de interés (VOI), información, etc.
2.2.7.
Aplicación de los datos de imágenes
Las clases de imagen SOP, en general, se generan en aparatos médicos o
en estaciones de trabajo dedicadas a procesamiento. Las clases de imagen
SOP se visualizan en estaciones de revisión o son imprimidas sobre pelı́cula.
Los sistemas de almacenamiento guardan en el búfer las imágenes en un
fase intermedia o archivan estas imágenes por referencia en un estado
posterior. Los requerimientos para la información contenida en la instancia
de imagen SOP (Image SOP Instance) difieren para cada tipo de sistema
el cual está envuelto en el ciclo de vida de una imagen.
Intercambiando datos entre sistemas, cada sistema puede tener una diferente visión de la información, pero se debe tener mucho cuidado con que
toda la información en la instancia de imagen SOP sea transferida entre cada sistema involucrado. Incluso cuando un sistema en una cadena no usa la
información, otro sistema, que sı́ que la usa en una fase posterior, está confiando en el paso completo de la información en la cadena entera, ver figura
(2.18).
r
GVA-ELAI-UPMPFC0074-03
47
CAPÍTULO 2. ESTADO DE LA TÉCNICA.
José Ma Onrubia
Figura 2.18: Ciclo de vida de Image SOP Instance Information
Sistemas de almacenamiento de imágenes
Los sistemas de almacenamiento de imágenes usan un número de
atributos identificatorios para almacenar las instancias de imagen SOP.
En primer lugar, estos atributos se usan para recoger todos los datos
de las imágenes pertenecientes al mismo estudio. La instancia UID del
estudio (Study Instance UID) es el atributo clave. Pero cuando éste no se
usa consistentemente, se tienen que usar otros atributos como el ID del
paciente, número de acceso, etc.
En segundo lugar, unos atributos pueden ser usados por sistemas que
quieren encontrar instancias de imagen SOP en el sistema de almacenamiento. La clave principal en este caso es la instancia UID del estudio y
la instancia UID de la serie. Son posibles también búsquedas basadas en el
nombre del paciente, fecha del estudio, etc.
Para el uso de sistemas de almacenamiento un valor muy significativo
para estos tipos de atributos se tiene que suministrar por los creadores de la
instancia de la imagen SOP. Los atributos que contiene los parámetros de
adquisición y los datos de la imagen se almacenan pero no tienen significado
para un sistema de almacenamiento.
48
r
GVA-ELAI-UPMPFC0074-03
2.2. INSTANCIAS SOP DE IMÁGENES DICOM (DICOM IMAGE SOP
José Ma Onrubia
INSTANCES)
Estaciones de revisión
Una estación de revisión es básicamente usada para visualizar las
imágenes hechas en una o varios aparatos. Recoge o busca las instancias de
imagen SOP, en un sistema de almacenamiento, perteneciente a un cierto
estudio. Mostrará la imágen junto a la información del paciente, ajustes de
adquisición, información del diagnóstico, etc.
Los ajustes paraa el proceso de presentación, como los seleccionados en el
aparato de captura, son muy importantes. Cuando los pasos de presentación
se procesan de forma correcta, los resultados mostrados deberı́an ser iguales
a los originales mostrados por el aparato médico de captura de la imagen.
Para información adicional de otros sistemas, se usan atributos identificadores como la instancia UID del estudio.
Estaciones de procesamiento de imágenes
Las estaciones de trabajo capaces de procesar los datos de las imágenes
tienen requerimientos adicionales. Se necesitan los parámetros de adquisición
y posicionamiento para la realización de pasos adicionales de procesamiento.
Dependiendo en el tipo de procesamiento la entrada es un conjunto de
imágenes procesadas o no procesadas. En este caso la relación entre las
imágenes es importante ordenar los datos de las imágenes de forma correcta
para el procesamiento.
Los resultados de este procesamiento son nuevos datos de pı́xeles que son
almacenados en una nueva instancia de imagen SOP que tiene su propio ciclo
de vida con, en la mayorı́a de los casos, relaciones con los datos originales
usados por esta imagen.
Reutilización de datos
Una categorı́a final de las aplicaciones es el sistema que ha creado la
instancia de imagen SOP. En este caso los datos antiguos de la imagen
pueden ser usados cuando hay una nueva visita del mismo paciente con el
mismo tipo de examinación. Los datos de adquisición y el posicionamiento
pueden ser reutilizados, o la imagen puede ser visualizada como una
referencia para el nuevo examen.
r
GVA-ELAI-UPMPFC0074-03
49
CAPÍTULO 2. ESTADO DE LA TÉCNICA.
José Ma Onrubia
Categorı́as de aplicación
Como lo mostrado arriba, las exigencias de los sistemas individuales en el
ciclo de vida de una una instancia de imagen SOP son diferentes. Cuando
un sistema produce los datos de la imagen, debe estar alerta de que todos
los sistemas que están intentando ser parte del ciclo de vida deben recibir
suficiente información. El estatuto de conformidad (conformance statement)
debe describir, para cada tipo de sistema, la información adecuada y que
procesamiento no pueden ser aplicados.
Para ayudar a la selección de estos tipos de sistemas, los requerimientos
pueden ser divididos en categorı́as de aplicación. Una categorı́a alta
numerada incluye la categorı́a baja numerada. Se definen las siguientes
categorı́as:
1. Categorı́a de almacenamiento: sólo identifica los atributos requeridos.
2. Categorı́a de visualización: sólo se requieren los atributos para una
correcta presentación.
3. Procesamiento simple - medidas de volumen y distancia: requiere
algunos atributos más que describan qué información está en la imagen.
4. Procesamiento complejo - sustracción de imagen y MRP: requiere
información especı́fica sobre el posicionamiento y relaciones.
El comité de estandarización DICOM está considerando una clasificación
como la lista vista arriba para ser incluida en el estatuto de conformidad.
50
r
GVA-ELAI-UPMPFC0074-03
Capı́tulo 3
Estudio de librerias
DCMTK.
3.1.
Visión general.
La tecnologı́a de la información y la comunicación poco a poco está llegando a ser omnipresente en el cuidado de la salud.
Los requerimientos para un rápido acceso a los datos médicos en el
momento necesario sólo se puede conseguir mediante los estándares. El
estándar de DICOM facilita el intercambio y el procesamiento de imágenes
biomédicas de forma digital. Los aparatos de adquisición de imágenes,
archivos de imágenes y las estaciones de trabajo de diferentes vendedores,
pueden estar conectadas en una infraestructura común e integradas con
otros sistemas de información. Nuevas oportunidades se alzan, no sólo
dentro del hospital, también para el intercambio de información entre
diferentes clı́nicas y entre hospitales y prácticas médicas.
3.1.1.
Introducción.
La importancia del procesamiento de imágenes médicas a crecido permanentemente desde la introducción de la tomografı́a computada como primer
aparato digital en 1970.
La idea de unas imágenes digitales y una distribución electrónica de
éstas en el hospital creó la necesidad de intercambiar las imágenes digitales
entre recursos de diferentes vendedores. En 1983 se formaron los grupos de
American College of Radiology (ACR) y el National Electrical Manufacturers Association (NEMA) con el objetivo de descubrir un estándar para
el intercambio. Los trabajos resultaron en el estándar ACR-NEMA, el cuál
51
CAPÍTULO 3. ESTUDIO DE LIBRERIAS DCMTK.
José Ma Onrubia
fue publicado en 1985. Sin embargo este estándar no tuvo éxito devido a
una cierta debilidad conceptual.
El estándar de DICOM (Digital Imaging and Communications in
Medicine) fue creado desde las bases del ACR-NEMA para crear y abrir
una plataforma para la comunicación de imágenes y datos relacionados.
Además de este soprte, la garantı́a de interoperatividad entre aparatos
DICOM y programas fue la parte central de su éxito. DICOM fue publicado
en 1993 y se está extendiendo continuamente desde entonces. DICOM fue
aceptado como estándar formal en Europa en 1995.
3.1.2.
Descripción.
Los contenidos del standard de DICOM van más allá de una definición
del formato de los datos de las imágenes médicas.
DICOM define:
Estructuras de datos (formatos) para imágenes médicas y datos
relacio-nados,
Servicios orientados a la red.
Formatos para el almacenaje de medios de intercambio.
Requerimientos para el acuerdo de recursos y programas.
3.1.3.
Estructura de datos DICOM.
Una imagen DICOM consiste en lista de elementos de datos (llamados
atributos) que contiene una multitud de imagen la información relacionada:
paciente (nombre, sexo, identificación, número)
aparatos y procedimiento de imagen(parámetros de dispositivo, calibración, dosis de radiación, medios de comunicación de contraste),
imagen (resolución, windowing)
DICOM con precisión define para cada aparato, los elementos de
datos son requeridos, los q son opcionales y que es requerido en ciertas
circunstancias. Esta flexibilidad sin embargo, tan poderoso como es, es
también una debilidad del estándar porque la experiencia práctica muestra
que las imágenes son con frecuencia incompletas: los campos requeridos
52
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
3.1. VISIÓN GENERAL.
omiteno contienen valores incorrectos. Esto puede conducir a problemas en
el intercambio de datos.
3.1.4.
Servicios de red DICOM.
Los servicios de red de DICOM están basados en los concepto de cliente
/ servidor. Antes de que dos aplicaciones DICOM puedan intercambiar la
información, ellas deben establecer una conexión y estar de acuerdo sobre
los parámetros siguientes:
Quien es el cliente y quien es el servidor,
que servicios DICOM deben ser usados,
y en que formato los datos son transmitidos (Comprimido o incomprimido).
Sólo si ambas aplicaciones están de acuerdo en un unos parámetros
comunes, la conexión se establece.
3.1.5.
Intercambio de medios de comunicación.
Además de la comunicación de imágenes médicas sobre la red, el intercambio de medios de comunicación se ha hecho otro foco en DICOM que
ha sido integrado en el estándar sólo en la edición 1996. Los campos de
aplicación son por ejemplo el almacenaje o la pelı́culas de angiografı́as en
la cardiologı́a o el almacenaje de imágenes de ultrasonido. Para asegurarse
de que los medios de comunicación de almacenaje DICOM son realmente
intercambiables, el estándar define los llamados ”perfiles de aplicación ”que
explica detalladamente.
que aparatos pueden estar presentes en el medio
que formatos de codificación y compresión pueden ser usados
que medio de almacenaje debe ser usado
Cada medio DICOM contiene un llamado ”DICOM directorio .además
de los archivos de imagen. Este directorio contiene la información más
importante (el nombre paciente, la modalidad, identificadores únicos
etc.) para todas las imágenes en el medio. Esto permite hojear o buscar
rápidamente sin haber de necesidad de leer el medio completo.
r
GVA-ELAI-UPMPFC0074-03
53
CAPÍTULO 3. ESTUDIO DE LIBRERIAS DCMTK.
3.1.6.
José Ma Onrubia
Estatuto de conformidad.
DICOM requiere que una Declaración de Conformidad sea escrita para
cada dispositivo o la reclamación de programa para ser DICOM conformant. El formato y el contenido de esta declaración son definidos en el
estándar. Esto explica que servicios DICOM y opciones son soportados, que
extensiones y particularidades han sido puestas en práctica por el vendedor,
y como el dispositivo se comunica con otros sistemas DICOM. En la teorı́a,
comparando dos declaraciones de conformidad permite determinar si dos
dispositivos DICOM son capaces de comunicarse el uno con otro.
En la práctica, sin embargo, las declaraciones de conformidad son sólo
comprensibles para expertos y son con frecuencia inadecuados.
3.1.7.
Conclusión.
DICOM se ha hecho un componente indispensable para la integración
de sistemas de imagenes digitales en la medicina. DICOM ofrece soluciones para una multitud de comunicación aplicaciones relacionadas. La
palabra clave ”DICOM”solo, sin embargo, no es ninguna garantı́a para una
integración ”de enchufar y listo”de todos los sistemas de información en
hospital. Esto requiere una combinación cuidadosa de todas las soluciones
parciales ofrecidas por DICOM.
DCMTK es el software DICOM proporcionado gratuitamente por
OFFIS-DICOM, el cual se puede descargar de la página web.
DCMTK es una colección de librerı́as y aplicaciones que implementan
las partes del estándar DICOM para la comunicación de imagen médica.
Esto incluye el software para el examen, la construcción y la conversión
archivos de imagen DICOM, el manejo medios de comunicación autónomos,
el envı́o e imágenes de encubrimiento sobre una conexión de red, ası́ como
la demostración del almacenaje de imagenes y servidores worklist. DCMTK
incluye el código fuente completo y está escrito en una mezcla de C ANSI
y la C ++.
DCMTK ha sido usado en numerosas demostraciones DICOM para
proporcionar central, el vendedor independiente, el almacenaje de imagen
y servidores worklist (CTNs - Nodos Centrales De prueba). Es usado por
hospitales y empresas en todo el mundo para una amplia variedad de
propósitos desde ser una herramienta para pruebas de productos, a ser un
componente básico para proyectos de investigación, prototipos y productos
comerciales
54
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
3.2. INSTALACIÓN DCMTK351.
El software DCMTK puede ser compilado bajo el Windows NT o una
amplia gama de sistemas operativos Unix que incluyen Linux, Solaris,
OSF/1, IRIX, FreeBSD y MacOS X. Todos los guiones de configuración
necesarios y ”makefiles”de los proyecto son suministrados.
Trabajar con esta herramienta es muy arduo y dificultoso debido a la
poca documentación, a la dificultad que entraña el trabajar con todos
los términos DICOM y a la amplitud del código. Por estas razones y
por alguna más es más aconsejable trabajar con una nueva herramienta
que cuenta con la desventaja de que no es gratuita pero con las ventajas
de una gran documentación plenamente estructurada y el trabajar con Java.
3.2.
Instalación dcmtk351.
OfficeDicom ofrece la posibilidad de conseguir gratuitamente de su
página web, http://www.offis.de, el Toolkit dcmtk351, donde se encuentra
el estándar DICOM implementado en código C++. Para la instalación del
toolkit de OfficeDicom en un sistema operativo basado en Windows, hay
que descomprimir el archivo dcmtk531.zip. Entonces abriremos el proyecto
dcmtk.dsp y lo compilaremos y construiremos con el Visual C++, este
proyecto se encuentra en X:/.../Toolkit/source/dcmtk. Esto creará todos
los ejecutables y archivos .obj y .lib en una carpeta llamada OpenSSL de
cada una de las funciones existentes en este toolkit las cuales podrán ser
utilizadas en otros proyectos, bastando incluirlas en éstos.
Este Toolkit tiene diferentes funciones basadas en el estándar Dicom.
Hay varias carpetas con los archivos fuente de las funciones. Las funciones
son agrupadas en carpetas dependiendo de la función que desempeñen.
Config: Incluye los ficheros .h necesarios para la configuración del
toolkit.
Dcmdata: Contiene funciones para el tratamiento de los datos de los
archivos Dicom y Data Sets.
Dcmimage: Fuciones para el tratamiento de los datos de los pixel de
una imagen. Sólo para imágenes Dicom sin comprimir.
Dcmimgle: Sirven para el tratamiento de la luminosidad de las
imágenes.
r
GVA-ELAI-UPMPFC0074-03
55
CAPÍTULO 3. ESTUDIO DE LIBRERIAS DCMTK.
José Ma Onrubia
Dcmjpeg: Son funciones para la compresión/descompresión de
imágenes DICOM a JPEG.
Dcmnet: Funciones para el transporte de los archivos Dicom a través
de la Red.
Dcmpstat: Funciones para el tratamiento de escalas de grises y estados
de presentación.
Dcmsing: Para la creación o supresión de una firma digital para un
archivo Dicom y su verificación.
Dcmsr: Para la conversión de documentos Dicom SR (Structured Reporting) a HTML, XML .
Dcmtls: Para la transmisión segura de archivos Dicom por la Red.
Imagectn: Para el registro de archivos en una base de datos.
Wlistctn: Para implementar un SCP como una Base de Datos.
Nos centraremos en las funciones para el transporte de archivos y la
compresión a Jpeg.
Figura 3.1: Visual C++ con DCMTK
56
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
3.2.1.
3.2. INSTALACIÓN DCMTK351.
Dcmnet.
Echoscu: Esta aplicación implementa un Service Class User (SCU)
para la verificación SOP Class.Envı́a un mensage Dicom C-ECHO a
un Service Class Provider (SCP) y espera una respuesta.
Findscu: Esta aplicación implementa un Service Class Query/Rerieve
(petición/recuperación) y un Service Class Basic Worklist Management. Sólo soporta el mensage Dicom C-FIND, que envı́a una petición
al SCP y espera respuesta.
Movescu: Esta aplicación implementa un SCP para el Service Class
Query/Retrieve y un SCU para el Storage Service Class. Para usar
la funcionalidad Retrieve (Recuperación) usa el mensage Dicom CMOVE que envı́a una petición al SCP y espera respuesta. El SCP
aceptará la asociación para recibir imágenes enviadas como resultado
de la petición C-MOVE. El término MOVE es poco apropiado, ya que
lo que hace es una copia de la imagen, la imagen nunca se borra del
SCP.
Storescp: Implementa un Service Class Provider (SCP) para el Storage
Service Class. Se pone a la escucha sobre un especı́fico puerto TCP/IP,
para las peticiones de asociación que puedan llegar de un Storage SCU
y puede recibir imágenes según el Storage Service Class.
Storescu: Implementa un Service Class User (SCU) para el Storage
Service Class.Se usa para transmitir imágenes Dicom. Envı́a un mensage C-STORE a un Storage SCP y espera respuesta.
Aplicación para ver la conectividad entre dos máquinas.
Esta aplicación la realizaremos sobre dos máquinas, una será Galileo que
actuará de SCP y otra será Gauss que será el SCU. Pondremos la opción -v
la cual nos dirá en todo momento que asociación se está realizando, dando
detalles sobre ella.
Paso 1o : Realizamos una aplicación Dicom Storage/Verification Service
Class Provider. Ponemos un puerto a la escucha (el puerto 104 es el más
utilizado en Dicom) para la llegada de asociaciones.
Galileo¿storescp -v 104
Paso 2o : Comenzamos una aplicación Dicom Verification Service Class
User. Esto intentará construir una asociación Dicom con una aplicación que
corra sobre Galileo, conectándolos por el puerto 104. Gauss enviará una
petición C-ECHO y estará a la espera de una respuesta C-ECHO de Galileo.
r
GVA-ELAI-UPMPFC0074-03
57
CAPÍTULO 3. ESTUDIO DE LIBRERIAS DCMTK.
José Ma Onrubia
Esto es sólo para verificar que hay conexión entre las dos máquinas.
Gauss>echoscu -v Galileo 104
Paso3o : Enviamos una imagen Dicom a Galileo (SCP). Volveremos a
intentar realizar una asociación Dicom con una aplicación que corra sobre
Galileo. Enviamos una petición C-STORE que contiene una imagen Dicom
çraneo.dcm esperamos una respuesta C-STORE de Galileo.
2
Gauss>storescu -v Galileo 104 craneo.dcm
La imagen se guardará en el lugar de trabajo donde esté realizandose
la escucha del puerto 104. Por ejemplo si lo hemos hecho en un fichero
C:/Dicom, la imagen será guardada en ese fichero. El nombre que tendrá la
nueva imagen copiada en Gauss, será a priori su UID, que será único entre
todas las imáges DICOM que tengamos.
3.2.2.
Dcmjpeg.
Dcmcjpeg: Realiza la compresión de una imagen DICOM a una imagen
JPEG.
Dcmdjpeg: Descomprime la imagen DICOM comprimida como JPEG.
Dcmj2pnm: Lee una imagen DICOM y convierte los datos de los pixel según las opciones del procesamiento de imágenes seleccionadas,
PPM/PGM, BMP, TIFF o JPEG.
Dcmmkdir: Crea un archivo DICOMDIR de los archivos DICOM especificados según la aplicación Media de almacena.
3.3.
DicomScope.
El DicomScope es un programa desarrollado en C++ y su entorno de
ventanas en Java. Permite visualizar, imprimir, almacenar, transmitir y
recibir estudios, imágenes, estados de presentación e informes estructurados
. Los informes estructurados (SR) consisten en informes completos de
diagnóstico y resultados de un examen en particular.
La aplicación tiene cuatro partes principales:
Browser (Navegador de estudios): El cual es la base de datos local de
la aplicación donde se encuentran los estudios (imágenes, structured
58
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
3.3. DICOMSCOPE.
reports,...) de la aplicación.
Viewer: Para tratar y mostrar imágenes Dicom, imágenes de escalas
de grises, estados de presentación e informes estructurados.
Print: Administra e incluye los estudios para su impresión.
Process log: Muestra los procesos que se han llevado a cabo en la
transmisión de archivos Dicom.
3.3.1.
Instalación.
Es necesario para la instalación un sistema compatible con Java
v1.3 y Windows 32 bits. Antes de la instalación del DicomScope
es necesaria la instalación de Java 2 SDK o JRE(Java 2 Runtime
Environment), para conseguir esto, se puede bajar de la página
http://java.sun.com/j2se/1.4.1/download.html. Tan sólo hay que ejecutar el Setup y seguir las instrucciones dadas.
3.3.2.
Browser.
Es la base de datos del DicomScope donde se almacenan los estudios
Dicom. Tiene una estructura de árbol en la que cada estudio es una rama,
y puede tener varias ramas a su vez, puede tener imágenes, informes
estructurados, imágenes de escalas de grises y estados de presentación.
Los nuevos estudios recibidos por Red o almacenados en la aplicación,
se di-ferenciarán de los otros por que aparece un sı́mbolo de ”New.a su
izquierda, una vez visualizados éstos, perderán el sı́mbolo. Para enviar
estudios a otra máquina, hay elegir el estudio que queramos en-viar y
presionar la tecla send, entonces se abrirá una ventana en la que hay que
elegir la forma de enviar los estudios, hay tres formas:
Transmisión insegura, sin protección de los datos en tránsito.
Transmisión TLS , en la que se utilizan certificados para la transmisión
de datos.
Transmisión TLS y encriptación.
Para poder configurar a que máquinas van a ir los estudios enviados
y que puerto utilizan para la asociación, se hace mediante el archivo
DICOMscope.cfg que se encuentra en .../DICOMscope351, escribiendo a
que hostname quiere ser en-viado y el port.
r
GVA-ELAI-UPMPFC0074-03
59
CAPÍTULO 3. ESTUDIO DE LIBRERIAS DCMTK.
José Ma Onrubia
Figura 3.2: Browser
3.3.3.
Viewer.
Todas las instancias Dicom que se carguen, pasarán a verse en el
Viewer. Es una herramienta para tratar las imágenes Dicom y cambiar y editar informes estructu-rados, incluso para verificarlos y crear firmas digitales.
60
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
3.3. DICOMSCOPE.
Figura 3.3: Viewer
3.3.4.
Print.
Se pueden enviar imágenes Dicom a imprimir desde el Browser o la
imagen que se está visualizando en el Viewer. Esto lleva la imagen al Print
en el que se vi-sualiza la imagen que se va a imprimir.
r
GVA-ELAI-UPMPFC0074-03
61
CAPÍTULO 3. ESTUDIO DE LIBRERIAS DCMTK.
José Ma Onrubia
Figura 3.4: Print
3.3.5.
Process Log.
Se puede ver que procesos se producen para la transmisión de archivos
Di-com. Al iniciar el DicomScope se ve que hay dos procesos que están
realizándose.
Uno es para que el DicomScope sirva como receptor de instancias Dicom con transmisión insegura, sin utilizar TLS. Este proceso utiliza la
orden C-STORESCP, con esto recibe y guarda en la base de datos los
archivos Dicom mandados a este equipo, utilizando el puerto 10004.
El otro proceso recibe las instancias Dicom utilizando TLS, siendo de
esta forma segura la transmisión de datos. También utiliza la orden
C-STORESCP y el puerto elegido es el 10007.
62
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
3.3. DICOMSCOPE.
Figura 3.5: Process log
r
GVA-ELAI-UPMPFC0074-03
63
CAPÍTULO 3. ESTUDIO DE LIBRERIAS DCMTK.
64
José Ma Onrubia
r
GVA-ELAI-UPMPFC0074-03
Capı́tulo 4
JDT (Java DICOM Toolkit)
4.1.
Introducción.
Java DICOM Toolkit es la ayuda para un programador en JAVA para
construir una aplicación que siga lo marcado por el estándar DICOM 3.0.
Combina las ventajas y la fuerza de DICOM y JAVA en una .API”muy
fácil de usar. Proporciona numerosas clases y métodos que simplifican la
programación de DICOM.
JDT es el primer equipo de desarrollo de software DICOM que está implementado totalmente en JAVA. Con esto, los desarrolladores DICOM pueden
beneficiarse de las numerosas ventajas del lenguaje de programación JAVA
y desplegarlo en DICOM .applets”, aplicaciones independientes JAVA y en
software de servidor. JDT viene con una .API”bien documentada que ha
sido diseñada para hacer que la estructura compleja del estándar DICOM
sea más accesible para los desarrolladores. JDT funciona sobre JDK 1.1.X
y la JAVA 2.
Caracterı́sticas:
Soporte de la parte 10 del estándar DICOM.
Soporte de red DICOM.
Soporte para todas las ”transfer syntax”no comprimidas y conversiones.
Soporte para formatos RLE y JPEG.
Leer y escribir datos DICOM desde InputStreams/OutputSreams.
Esquema de tipos JAVA a tipo tipos DICOM.
Tolerancias en implementaciones DICOM.
65
CAPÍTULO 4. JDT (JAVA DICOM TOOLKIT)
4.2.
Guia de usuario de JDT.
4.2.1.
Terminologı́a.
José Ma Onrubia
En esta sección se usa palabras como conjunto de datos (dataset) y atributo. Conjunto de datos se usa para identificar una colección de atributos
DICOM. Un atributo se identifica por su par (número de grupo, número de
elemento), tiene un cierto tipo DICOM (value representation - VR)
4.2.2.
Conjunto de datos (Datasets).
Introducción.
En JDT, todos los conjuntos de datos están representados por
com.archimed.dicom.DicomObject. Esta clase es una subclase de
com.archimed.dicom.GroupList. Básicamente es donde residen los atributos
DICOM (com.archimed.dicom.TagValue).
Manipulación de atributos.
Un conjunto de datos DICOM es representado por un DicomObject. Los
diferentes atributos de estos conjuntos de datos están internamente almacenados en el DicomObject como objetos com.archimed.dicom.Tagvalue. El
objeto TagValue contiene un par (grupo,elemento) y los valores del atributo
están almacenados en un Vector. El tamaño del Vector corresponde a la
multiplicidad del atributo. El tipo JAVA que representa el valor de un
atributo depende del tipo DICOM (Value Representation - VR) definido
para ese atributo especı́fico. La siguiente tabla muestra la equivalencia entre
los tipos DICOM y sus correspondientes tipos JAVA.
Las conversiones soportadas a y desde tipos que no son los tipos por
defecto están en cursiva.
Manipulación de atributos simples. Hay un número de métodos
set/get en DicomObject con los que se puede meter, sacar o modificar los
atributos guardados en un DicomObject. La forma de hacer esto es con
la clase com.archimed.dicom.DDict. La clase DDict tiene una constante
definida para cada atributo definido en el estándar DICOM. Por ejemplo:
DDict.dPatientName
DDict.dAccessionNumber
Esas constantes pueden ser usadas en los métodos set/get del DicomObject:
Person p = (Person)dcm.get(DDict.dPatientName);
66
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
tipo Java
Short
Integer
Long
Float
Double
byte[]
int[]
String
Person
DDate
DDateRange
4.2. GUIA DE USUARIO DE JDT.
tipo DICOM
SS
US, US—SS, IS, AT, SS, SL, UL
SL, UL
FL, DS
FD
OB, OW, OW—OB
AT (int[2])
AS, AE, CS, LO, LT, SH, ST, UI, TM, PN, DA,
DS, IS, SS, US, SL, UL, FL, FD, OB, OW, OW—OB
PN
DA
DA
Cuadro 4.1: tipo Java / tipo DICOM
Integer acnumber = (Integer)dcm.get(DDict.dAccessionNumber);
dcm.set(DDict.dPatientName, new Person(”Jose”));
dcm.set(DDict.dAccessionNumber, new Integer(12345));
El método set implı́citamente convierte el valor del argumento dado al
tipo DICOM correcto.
También se puede acceder a los atributos de un DicomObject a través del
par (grupo.elemento).
Person p = (Person)dcm.get ge(0x0010, 0x0010);
Integer acnumber = (Integer)dcm.get ge(0x0008,0x0050,DDict.dAccessionNumber);
dcm.set ge(0x0010, 0x0010, new Person(”Jose”));
dcm.set ge(0x0008, 0x0050, new Integer(12345));
Hay también dos métodos get que convierten directamente a String o int:
String s = dcm.getS(DDict.dPatientName);
int i = dcm.getI(DDict.dAccessionNumber);
r
GVA-ELAI-UPMPFC0074-03
67
CAPÍTULO 4. JDT (JAVA DICOM TOOLKIT)
tipo DICOM
AE
AT
AT
CS
DA
DS
FL
FD
IS
LO
LT
OB
OW
OB—OW
PN
SH
SL
SS
ST
TM
UI
UL
US
US—SS
José Ma Onrubia
tipo Java
String
String
Integer (0xggggeeee)
String
DDate or DDateRange
Float
Float
Double
Integer
String
String
byte[]
byte[]
byte[]
Person
String
Long
Short
String
String
String
Long
Integer
Integer
Cuadro 4.2: tipo DICOM / tipo Java
Para manipular atributos con una multiplicidad mayor de uno, se usan
los métodos get/set con un argumento adicional. La multiplicidad de
un atributo se obtiene con getSize(). Por ejemplo, suponiendo que un
DicomObject dcm contiene un atributo ImageType con multiplicidad 2 y
valores DERIVED/SECONJDARY, entonces se puede coger esos valores
de la siguiente forma:
int multiplicity = dcm.getSize(DDict.dImageType); //devolverá el valor 2
String str1 = (String)dcm.get(DDict.dImageType,0);
valor ’DERIVED’
//devolverá el
String str2 = (String)dcm.get(DDict.dImageType,1);
//devolverá el
68
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
4.2. GUIA DE USUARIO DE JDT.
valor ’SECONDARY’
Insertando el valor de un atributo ocurre lo mismo:
dcm.set(DDict.dImageType,0,”DERIVED”);
dcm.set(DDict.dImageType,1,”SECONDARY”);
Secuencias.
Las secuencias se tratan de una forma parecida que los valores de
multiplicidad mayor de uno. Cuando un atributo en un DicomObject
representa una secuencia (tipo SQ DICOM), entonces los artı́culos de
la secuencia pueden ser insertados y cogidos con los mismos métodos
get/set del DicomObject que ahora aceptan y devuelven los DicomObejct´s
completos. Por ejemplo, suponiendo que el DicomObject dcm contiene un
atributo DirectoryRecordSequence con un cierto número de artı́culos:
int numberofitems = dcm.getSize(DDict.dDirectoryRecordSequence);
DicomObject item0 = (DicomObject)dcm.get(DDict.dDirectoryRecordSequence,0);
DicomObject item1 = (DicomObject)dcm.get(DDict.dDirectoryRecordSequence,1);
Para añadir un valor a una secuencia (Sequence), simplemente usando el
método set que tiene el DicomObject que representa el artı́culo y el ı́ndice
del artı́culo.
Para un rápido acceso, hay una utilidad de la clase
com.archimed.dicom.tools.Sequences que contiene varios métodos para
acceder a las secuencias. También cuida de todas las diferentes excepciones
encontradas. El nombre elegido para los métodos son muy similares que los
encontrados en el DicomObject.
Comentarios:
las longitudes de los grupos no se almacenan en un DicomObject, se
calculan cuando se necesitan, ası́ que no hay acceso a ellos.
cuando usamos set para insertar valores de atributos, los valores se
alamacenan por referencia y no se copian.
cuando usamos get para sacar valores de atributos, se devuelve una
referencia al valor.
r
GVA-ELAI-UPMPFC0074-03
69
CAPÍTULO 4. JDT (JAVA DICOM TOOLKIT)
José Ma Onrubia
Manipular grupos de atributos.
Para usuarios que quieran manipular los grupos enteros
del conjunto de datos, hay el acceso al grupo proporcionado
por com.archimed.dicom.GroupList, el cual es la superclase de
com.archimed.DicomObject. Un grupo es un conjunto de atributos
que tienen el mismo número de grupo en su par (grupo,elemento).
DicomObject copyGroup(int groupnr) copia el grupo con el número de
grupo y lo devuelve como un DicomObject nuevo. Notar que sólo se hace
una copia no profunda, sólo se copian referencias a los atributos.
Void addGroups(DicomObject o) añade todos los grupos encontrados al
conjunto de datos. Sólo se añaden los grupos que no estuvisen presentes en
este conjunto de datos. Otra vez, se hace sólo una copia superflua.
DicomObject removeGroup(int groupnr) borra el grupo entero con el
número de grupo del conjunto de datos y lo devuelve como un DicomObject.
I/O de conjuntos de datos DICOM.
Nosotros tenemos varias formas para leer o escribir datasets DICOM
desde y por InputStreams/OutputStreams. En ambos casos hay un método
básico y varios métodos que lo hacen posible para especificar todo tipo de
parámetros.
Leer conjunto de datos(dataset).
void read(java.io.InputStream in)
Este método lee todos los atributos DICOM desde un inputStream a un
DicomObject. El inputStream puede contener tanto un archivo DICOM
como un conjunto de datos DICOM. Cuando el inputStream contiene
un archivo de la parte 10 DICOM, se lee y se almacena la Meta File
Information en un DicomObject separado que se puede coger mediante
getFileMetaInformation(). La transfer syntax se asume que es Implicit
VR Little Endian cuando el inputStream contiene un conjunto de datos
DICOM. Cuando el inputStream contiene un archivo de la parte 10 de
DICOM, el transfer syntax se detecta desde la File Meta Information.
void read(java.io.InputStream in, boolean process)
Este método hace lo mismo que el anterior pero además permite especificar si se procesa o no se procesa los datos de pixel. Salva el tiempo de
proceso cuando no se necesita el pixel data.
70
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
4.2. GUIA DE USUARIO DE JDT.
void read(java.io.InputStream in, int ts, boolean process)
El parámetro ts especifica que transfer syntax se usa. Este parámetro
puede venir dado , cuando se conoce por adelantado con qué transfer syntax
se codificó el conjunto de datos.
Escribir conjunto de datos(dataset).
void write(java.io.OutputStream out, boolean f )
Este es el más básico método para exportar. Si la bandera f es ”true”, el
conjunto de datos se codifica como la parte 10 de DICOM. En este caso, la
File Meta Information se usa si está presente, o se crea cuando se necesita.
Nota que la creación de la File Meta Information puede lanzar una exección
cuando faltan atributos requeridos (SOP Class UID, SOP Instance UID).
void write(java.io.OutputStream out, boolean f, int ts, boolean seqUndef )
Los parámetros adicionales ts y seqUndef puede ser usado para escribir tu
conjunto de datos casi en todos los posibles tipos DICOM. Los parámetros
ts y seqUndef pueden ser usados para insertar la Transfer Syntax. Toda
posible combinación de parámetros ts y seqUndef se permiten, pero no
todas las combinaciones siguen los dictados del estándar de DICOM. Si
escribes un conjunto de datos con f ”true ts otra cosa que no sea Implicit
VR Little Endian, es imposible para otras aplicaciones para decodificar
ya que ellas no pueden detectar la sintaxis de transferencia usada. El
parámetro seqUndef indica al escribir secuencias si se usa indefinido (true)
o definida (false) la longitud.
2
Visualizar conjunto de datos.
DicomObject contiene dos métodos para imprimir todos lor atributos
que contiene hacia un OutputStream de forma ordenada para que el ser
humano sea capaz de interpretarla.
void dumpVRs(java.io.OutputStream os)
void dumpVRs(java.io.OutputStream os, boolean metainfo)
Poner metainfo a ”true”si se quiere ver File Meta Information.
Ejemplos.
r
GVA-ELAI-UPMPFC0074-03
71
CAPÍTULO 4. JDT (JAVA DICOM TOOLKIT)
José Ma Onrubia
Estos trozos de código demuestran el fácil uso de JDT. Con sólo unas
lı́neas de código, es posible construir soluciones poderosas DICOM.
El código siguiente lee un archivo DICOM desde un archivo y muestra
los atributos (incluidos los contenidos en la meta information si existe) por
la pantalla.
DicomObject dcm = new DicomObject;
dcm.read(new FileInputStream(”foo.dcm”));
dcm.dumpVRs(System.out, true);
El siguiente ejemplo lee los datos de un archivo y lo escribe en otro archivo
usando una transfer syntax y una secuencia de codificación especı́ficas.
DicomObject dcm = new DicomObject;
dcm.read(new FileInputStream(”in.dcm”));
dcm.write(new
FileOutputStream(.out.dcm”),
tax.ExplicitVRBigEndian, true);
true,
TransferSyn-
Métodos útiles.
Enumerar los atributos de un conjunto de datos(dataset).
Con el método enumerateVRs es posible conseguir una enumeración
(clase de java) de todos los atributos sontenidos en un DicomObject.
Enumeration e = dcm.enumerateVRs(false);
enumerateVRs() devuelve una enumeración de todos los atributos de
dcm como objetos TagValue. TagValue tiene métodos para coger el valor y
el par (grupo,elemento) de un atributo.
File Meta Information.
DicomObject fmi = dcm.getFileMetaInformation();
Devuelve la File Meta Information del DicomObject dcm si existe. Se
puede usar ahora fmi para añadir o alterar atributos especı́ficos de esta
información como se quiera.
72
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
4.2. GUIA DE USUARIO DE JDT.
Información general.
Unosm métodos de com.archimed.dicom.GroupList proporcionan información general sobre un conjunto de datos:
int numberOfElements() : devuelve el número total de atributos.
int numberOfGroups() : devuelve el número total de grupos.
boolean isEmpty() : devuelve si el GroupList contiene algún atributo.
boolean containsGroup(int g) : devuleve si el GroupList contiene el grupo
especificado.
4.2.3.
Depósitos.
Hay unas clases en el paquete com.archimed.dicom que hacen más fácil
para los programadores para usar los conjuntos de datos y las UID´s
registradas (se ha tratado de cubrir todo lo especificado en el estándar 3.6).
Clase DDict: depósito de atributos.
La clase com.archimed.dicom.DDict es un almacen de los VRs (value representations) y los elementos de datos. Contiene un número de constantes
que representan los diferentes VRs y un gran conjunto de constantes para
los elementos de datos:
DDict.tPN // representa el tipo DICOM PERSON.
DDict.tUS // representa el tipo DICOM UNSIGNED SHORT.
DDict.dAccesionNumber // representa el atributo AccessionNumber.
DDict.dPatientName // representa el atributo PatientName.
Los métodos de DDict.
La clase DDict tiene métodos para obtener el par (grupo,elemento) de un
atributo, un tipo de atributo, una descripción del atributo y para consultar
una constante DDict del atributo basada en su par (grupo,elemento).
r
GVA-ELAI-UPMPFC0074-03
73
CAPÍTULO 4. JDT (JAVA DICOM TOOLKIT)
José Ma Onrubia
static int getGroup(int dct) Devuelve el número de grupo para una
constante DDict que representa un atributo.
static int getElement(int dct) Devuelve el número de elemento para una
constante DDict que representa un atributo.
static int getTypeCode(int dct) Devuelve el tipo para una constante
DDict que representa un atributo. Los elementos de datos que no están en
la lista de arriba tendrán un DDict.tUNKNOWN.
static java.lang.String getDescription(int dct) Da una descripción elaborada para una constante DDict que representa un atributo.
static int lookupDDict(int g, int e) Devuelve la constante DDict que
representa el atributo con número de grupo g y número de elemento e. Si
no se encuentran constantes, el método devolverá DDict.dUNDEFINED.
Clase UID: depósitos UID.
La clase com.archimed.dicom.UID contiene un depósito de los UIDs
DICOM registrados (Parte 6 DICOM).Las constantes que representan los
UIDs y que tienen que ser usadas a través de JDT se definen en subclases
de UID:
com.archimed.dicom.TransferSyntax : constantes que representan las
transfer syntax.
com.archimed.dicom.SOPClass: constantes que representan las clases
SOP.
com.archimed.dicom.MetaSOPClass: constantes que representan las
clases Meta SOP.
com.archimed.dicom.SOPInstance: constantes que representan las bien
conocidas instancias SOP.
El objeto com.archimed.dicom.UIDEntry representa un único identificador y se obtiene con la clase UID de dos formas. Usando una constante
de una de las subclases UID:
UIDEntry entry = UID.getUIDEntry(TransferSyntax.JPEGBaseline);
o usando una cadena UID:
74
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
4.2. GUIA DE USUARIO DE JDT.
UIDEntry entry = UID.getUIDEntry(”1.2.840.10008.1.2.4.50”);
Cada uno de esos métodos de consulta devulve un objeto UIDEntry el
cual es contiene varias propiedades de el identificador único especı́fico. Esos
atributos pueden ser obtenidos usando los métodos get.
4.2.4.
Imágenes en JDT.
Esta parte habla de las capacidades de imagen de JDT. Todas las
clases relacionadas con las imágenes pueden ser encontradas en el paquete
com.archimed.dicom.image.
La clase DicomImage.
La
clase
base
para
las
imágenes
es
com.archimed.dicom.image.DicomImage. A parte de los métodos set/get
básicos para manipular los datos, inherentes a la DicomObject, contiene
otras formas de coger e insertar los atributos requeridos (tipo 1 y tipo 2)
que son comunes a todos los DICOM Image Modality IODs (ver parte 3 de
DICOM). Cuando se escribe una DicomImage a un outputstream, no hay
un reconocimiento de si todos los atributos requeridos están presentes.
Insertar datos que no son de imagen.
DicomImage contiene un número de métodos para insertar los atributos
requeridos que no están relacionados con los datos de imágen.Una corta
descripción son estos métodos:
void patientData(String patientName, String patientID, String birthDate,
String sex) inserta los datos del paciente.
void generalStudyData(String instanceUID, String date, String time,
String physName, String studyID, String orderNumber) inserta los atributos del estudio general.
generalSeriesData(String modality, String instanceUID, String seriesNumber) añade los datos generales de serie.
generalEquipmentData(String manufacturer)
generalImageData(String imageNumber)
r
GVA-ELAI-UPMPFC0074-03
75
CAPÍTULO 4. JDT (JAVA DICOM TOOLKIT)
José Ma Onrubia
sopCommonData(String sopClassUID, String sopInstanceUID) inserta los datos comunes SOP. SOP Class UID es tı́picamente uno de las
diferentes image storage SOP Classes, que pueden ser encontrados en
com.archimed.dicom.SOPClass.
Insertar datos de imagen con los métodos de DicomImage.
Hay también métodos en com.archimed.dicom.image.DicomImage que
pueden ser usados para insertar los datos de los pı́xeles de la imagen.
La clase contiene métodos para imágenes en escala de grises, en paleta
de colores y en RGB. Una definición de todos los parámetros pueden ser
encontrados en la API.
DicomImage dcmi = new DicomImage();
byte[] pixels = new byte[640*480]; // rellena este array con pı́xeles.
byte[] red = new byte[256]; // rellena este array con un LUT rojo.
byte[] green = new byte[256]; // rellena este array con un LUT verde.
byte[] blue = new byte[256]; // rellena este array con un LUT azul.
dcmi.imagePixelData(480, 640, pixels, red, green, blue);
Esto da una DicomImage con una interpretación fotométrica PALETTE
COLOR, tamaño 640x480 y con una profundidad de pixel de 8.
Insertando los datos de imagen con ImageProducer.
Hay otra forma de insertar los datos de la imagen. Dado una ImageProducer ip, construyebdo un objeto ImageIO y usando el método
setImageProducer() para copiar los datos de imagen desde la ImageProducer a la DicomImage:
DicomImage dcmi = new DicomImage();
ImageIO imgio = new ImageIO(dcmi);
imgio.setImageProducer(ip);
Cuando se llama al método setImageProducer(), todo los datos se copian
dentro de la DicomImage.
76
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
4.2. GUIA DE USUARIO DE JDT.
Esto es en teorı́a; después de muchas prácticas no ha sido posible
demostrar la validez de éste método, por lo que se recomiendo usar los
otros. (También se puede tratar de haver funcionar éste).
Obtenier una ImageProducer desde una DicomImage es también posible.
Todo marco simple de una imagen DICOM se puede coger como una
ImageProducer usando uno de los métodos siguientes:
java.awt.image.ImageProducer getImageProducer()
java.awt.image.ImageProducer getImageProducer(int i)
java.util.Vector getImageProducers()
Para imágenes de escalas de grises con profundidad de pixel mayor que 8 bits, hay un
color model (clase de java) especial
com.archimed.dicom.image.GrayColorModel. Este color model se usa
en combinación con un array int de pı́xeles, para producir imágenes de 256
grises sin pérdida de datos. Con este GrayColorModel, también es posible
meter el Window/Level usado en la producción de la imagen.
Insertar imagen con DicomObject.
Insertar y sacar los datos de imagen puede ser hecho directamente con
los set/get de la clase DicomObject. Los atributos de imagen como bits por
pı́xel, filas y coumnas se meten o sacan como cualquier otro atributo en un
DicomObject mediante las constantes de DDict. Los datos de pı́xel de una
imagen se almacenan en un DicomObject como un array o un número de
arrays dependiendo del formato de compresión:
no-comprimido transfer syntax, una imagen: un array de bytes que
mantiene el formato original de los datos de pı́xel definido en el
estándar DICOM, ejemplos:
• imagen MONOCHROME2, 8 bits asignados, 8 bits alamcenados:
1 elemento del array de bytes por pixel.
• imagen MONOCHROME2, 16 bits asignados, 12 bits alamcenados: 2 elementos consecutivos del array de bytes por pixel.
• imagen MONOCHROME2, 12 bits asignados, 12 bits alamcenados: 1 elemento y medio del array de bytes por pixel.
• imagen RGB, configuración plana color por pixel: 3 bytes consecutivos representando 1 pixel.
r
GVA-ELAI-UPMPFC0074-03
77
CAPÍTULO 4. JDT (JAVA DICOM TOOLKIT)
José Ma Onrubia
• imagen RGB, configuración plana color por plano: el array
de bytes está dividivo en 3 partes de igual longitud cada una
representando un color de plano (Red-Green-Blue).
Los array de bytes se cogen e insertan con los métodos
get(DDict.dPixelData) y set(DDict.dPixelData,¡byte array¿) respectivamente.
no-comprimido transfer syntax, varias imágenes: un array de bytes que
contienen marcos consecutivos.
comprimido transfer syntax, una imagen: un array de bytes en el formato original de compresion (ver compression).
Compression.
Los datos de pı́xel de una imagen DICOM se almacena en el atributo
DDict.dPixelData. Cuando una imagen DICO comprimida se lee desde un
inputstream, los pixeldata no se decodifican pero se almacenan internamente
en arrays de bytes en su formato de compresión por razones de rendimineto.
El tipo de codificación puede ser sacado de la sintaxis de transferencia en
el File Meta Information.
DcmObject dcm = new DicomObject();
dcm.read(new FileInputStream(ç://encodedimage.dcm”));
DicomObject fmi = dcm.getFileMetaInformation();
UIDEntry tsentry = UID.getUIDEntry(fmi.get(DDict.dTransferSyntaxUID));
System.out.println(”encoding: ”+ tsentry.getName());
Una utilidad de la clase com.archimed.dicom.codec.Compression es que
proporciona un número de decodificadores:
JPEG baseline
JPEG lossless
RLE Lossless
Todos los decodificadores están limitados a 8 bits por pı́xel. El decodificador JPEG puede manejar 1 o 3 muestras por pı́xel. RLE es sólo capaz de
78
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
4.2. GUIA DE USUARIO DE JDT.
descomprimir 1 muestra por pı́xel. El camino más fácil para descomprimir
imagen entera DICOM es construir un objeto Compression desde un
DicomObject y después llamar al método decompress. Éste descodifica los
datos del array de pı́xeles del DicomObject y los reemplaza por los datos
descomprimidos.
En el caso de una imagen DICOM multimarco, se puede decodificar el
array de bytes correspondioente a un marco individual. Primero obteniendo
un array de bytes de un marco con get(DDict.dPixelData, ¡index of
frame¿) y luego usando el método estático decompressframe() del objeto
Compression para obtener un array de bytes decodificado desde el array de
bytes comprimido.
static byte[] decompressframe(int encoding, byte[] frame, int width, int
heigth);
Los argumentos de codificación, ancho y alto que tienen que ser suministrados para usar decompressframe() se encuentran en la imagen DICOM
original.
r
GVA-ELAI-UPMPFC0074-03
79
CAPÍTULO 4. JDT (JAVA DICOM TOOLKIT)
4.3.
4.3.1.
José Ma Onrubia
Estructura de JDT(Java DICOM Toolkit).
Árbol de clases.
class java.lang.Object
class com.archimed.dicom.network.Association
class java.awt.image.ColorModel (implements java.awt.Transparency)
class com.archimed.dicom.image.GrayColorModel
class com.archimed.dicom.codec.Compression
class com.archimed.dicom.DDate
class com.archimed.dicom.DDateRange
class com.archimed.dicom.DDict
class com.archimed.dicom.DDictEntry
class com.archimed.dicom.Debug
class com.archimed.dicom.network.DimseUtil
class com.archimed.dicom.network.ExtendedNegotiation
class com.archimed.dicom.GroupList
class com.archimed.dicom.DicomObject
class com.archimed.dicom.image.DicomImage
class com.archimed.dicom.image.SCImage
class com.archimed.dicom.image.ImageIO
class com.archimed.dicom.Jdt
class com.archimed.dicom.Offsets
class com.archimed.dicom.Person
class com.archimed.dicom.network.Request
class com.archimed.dicom.network.Response
class com.archimed.dicom.network.Abort
class com.archimed.dicom.network.Acknowledge
class com.archimed.dicom.network.Reject
class com.archimed.dicom.network.ResponsePolicy
class com.archimed.dicom.tools.Sequences
class com.archimed.dicom.TagValue
class java.lang.Throwable (implements java.io.Serializable)
class java.lang.Exception
class com.archimed.dicom.DicomException
class com.archimed.dicom.IllegalValueException
class com.archimed.dicom.UnknownUIDException
class com.archimed.dicom.UID
class com.archimed.dicom.MetaSOPClass
class com.archimed.dicom.SOPClass
class com.archimed.dicom.SOPInstance
class com.archimed.dicom.TransferSyntax
class com.archimed.dicom.UIDEntry
class com.archimed.dicom.image.WL
80
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia4.3. ESTRUCTURA DE JDT(JAVA DICOM TOOLKIT).
4.3.2.
Paquetes.
Com.archimed.dicom.network.
Abort : Representa el aborto de una asociación. Los dos parámetros
son, la fuente y la razón del aborto.
Acknowledge : Estos objetos tienen los parámetros de la asociación Acknowledge, contiene todos los contextos de presentación del Acknowledge y son numerados desde 0 hasta el no de contextos de presentación
menos uno. Puede actuar como receptor de asociación o como iniciador
de la asociación.
Association : Contiene métodos para construir y destruir una asociación entre dos entidades de aplicación DICOM y mandar/ recibir
comandos y datos (data sets) una vez que la asociación está establecida.
DimseUtil : Las funciones DICOM que pueden hacerse.
ExtendedNegotiation: Representa los datos de negociación para un sintaxis abstracto.
Reject: Representa el rechazo de una asociación. Sus parámetros son
fuenta, resultado y razón.
Request : Representa todos los parámetros relevantes de una asociación
Request. Contiene todos los contextos de presentación y son numerados desde 0 hasta el no de contextos de presentación menos uno. Puede
actuar como receptor de asociación o como iniciador de la asociación.
Response: Representa una respuesta de un par de entidades DICOM.
Las clases implementadas son: Reject, Acknowledge y Abort.
ResponsePolicy: contiene dos tipos de métodos. Métodos para creación
de objetos Response, basados en una peticón dada y una polı́tica de
aceptación de la asociación. Métodos para el análisis de respuestas
Acknowledge, en el contexto de una petición dada.
Com.archimed.dicom.codec
Compression : Es una clase que proporciona métodos para la descompresión de datos de Pixel. DICOM soporta muchos tipos de técnicas
de compresión.
r
GVA-ELAI-UPMPFC0074-03
81
CAPÍTULO 4. JDT (JAVA DICOM TOOLKIT)
José Ma Onrubia
Com.archimed.dicom.image
DicomImage: Esta clase provee de métodos para construir una imagen
Dicom.
GrayColorModel : Esta clase representa un ColorModel para el empleo
con imágenes de Escala de gris.
ImageIO: Es una clase que proporciona métodos de convertir datos
de imagen almacenados a un ImageProducer (Productor de imagen) y
viceversa.
SCImage: Esta clase proporciona métodos para construir una imagen
SC.
WL: Es un contenedor básico para un par Ventana/Nivel.
Com.archimed.dicom.tools
Sequences: Estos objetos proveen los .atajos”para coger/poner valores
dentro de secuencias. La conversión de valores está hecha usando el
esquema de conversión DicomType-JavaType dada en la clase DicomObject.
Com.archimed.dicom
DDate: Esta clase representa la fecha de un objeto, conteniendo el dı́a,
mes y año. Se ha desarollado en correspondencia al tipo Dicom DA Es
útil, cuando se quiere buscar en una gama de fechas.
DDateRange: Esta clase representa la gama de fechas.
DDict: Esta clase provee de un diccionario (Diccionario de datos
Dicom) para los VRs y todos los elementos de datos.Cada par
(grupo,elemento) es accesible por una variable static int. Por ejemplo, (0010,0010) es representado por Ddic.dPatientName.
DDictEntry: Un objeto para una etiqueta que puede ser almacenado
en el diccionario de datos.
Debug: Proporciona una variable static int por si hay que imprimir
información de reparación de los errores a System.err.
DicomObject: Esta es la clase base de todos los datasets. Los métodos
de acceso proporcionados aquı́ son el modo de obtener/poner elementos
de dato (data elements) dentro de un objeto Dicom (DicomObject).
GroupList: Provee de métodos para el acceso de datos por grupo.
82
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia4.3. ESTRUCTURA DE JDT(JAVA DICOM TOOLKIT).
Jdt: Para obtener información sobre este Jdt
MetaSOPClass: Extensión de la clase UID.
Offsets : Esta clase proporciona utilidades para calcular compensaciones en un DicomObject que va a ser escrito.
Person: Esta clase representa el PN (Person Name) en Dicom.
SOPClass: Extensión de la clase UID.
SOPInstance: Extensión de la clase UID.
TagValue: Representa un par (grupo, elemento) y su valor.
TransferSintax : Extensión de la clase UID.
UID: Esta clase contiene un depósito de todos los UIDs Dicom certificados. Cada UID está en función del Transfer Syntax, SOPClass,
Meta- SOPClass y SOPInstance.
UIDEntry: Representa la entrada de un UID en el depósito, almacenándose.
DicomExcepcion: Indica que la aplicación ha violado la estructura y
codificación del Dicom Data.
IllegalValueExcepcion: Indica que un valor ilegal es leı́do durante una
asociación o cuando un valor ilegal es argumento de un método.
UnknownUIDExcepcion: Indica que el UID incluido no está definido
en la clase UID.
4.3.3.
Conclusiones.
Una vez trabajado y experimentado con los dos toolkit de DICOM,
dcmtk y JDT, se llegan a las siguientes conclusiones:
El toolkit dcmtk351 cuenta con la gran ventaja de ser un producto
gratuito, pero si no se es un gran experto tanto en materia DICOM como en
programación en C++, el estudio y la creación de una aplicación, nuestro
objetivo, se antoja demasiado complicado debido a la poca documentación
proporcionada con dicha herramienta y a la gran dificultad y amplitud del
código.
Por el contrario, JDT es un producto no gratuito, pero cuenta con las
grandes ventajas que el toolkit dcmtk351 no tiene. Lo primero a señalar
es que el lenguaje de programación es JAVA, con las ventajas que conlleva
r
GVA-ELAI-UPMPFC0074-03
83
CAPÍTULO 4. JDT (JAVA DICOM TOOLKIT)
José Ma Onrubia
con respecto a C++. Por otro lado, contiene una documentación amplia
y muy bien estructurada, lo que facilita enormemente el trabajo y su
comprensión. Contiene un árbol de clases, información de los diferentes
packages, ejemplos, las diferentes clases se estudian con detalle, es decir, de
que clases derivan, que métodos usan, que interfaces implementan, etc, lo
que todo junto hace mucho más fácil la implememtación.
Por todo lo visto anteriormente, a partir de este punto se empieza a trabajar con JDT, lo que nos conduce al estudio profundo de JAVA, por lo que
la siguiente sección trata de esto mismo: El lenguaje de programación JAVA.
84
r
GVA-ELAI-UPMPFC0074-03
Capı́tulo 5
Estudio de JAVA.
5.1.
Introducción
Java es la plataforma ideal para las soluciones de computación en red.
Ejecutable sobre las más diversas plataformas, desde servidores a teléfonos
móviles y tarjetas inteligentes, Java ofrece una infraestructura unica para
crear soluciones en red para su negocio.
Java está soportado por una gran comunidad de desarrolladores que
activamente trabajan en productos y servicios alrededor de Java, que al
mismo tiempo contribuyen a la evolución de la plataforma mediante el
Java Community Process, una organización estándar, abierta y basada en
comunidades.
Java está en teléfonos móviles, ordenadores portatiles, PDAs, en la
web, e incluso en los sistemas de las carreras de Formula 1. De hecho,
encontrará Java en cualquier lugar.
Beneficios de JAVA:
Java es simple: cuando usa un teléfono Java, juega o accede a su red
corporativa, Java ofrece la base de la verdadera movilidad. El excelente
compromiso entre movilidad y seguridad de la plataforma Java hace
posible el desarrollo y despliege de soluciones móviles e inalambricas.
Java es el entorno ideal para Web services: Java y XML son los dos
lenguajes más ampliamente aceptados en el mundo, ofreciendo una
plataforma real para cualquiera, en cualquier lugar, en cualquier momento, desde cualquier dispositivo.
Java está en todos los niveles de su negocio: Java ofrece un simple y
85
CAPÍTULO 5. ESTUDIO DE JAVA.
José Ma Onrubia
unificado modelo de programación que puede conectar todos los elementos de una infraestructura de negocio.
Java surgió en 1991 cuando un grupo de ingenieros de Sun Microsystems trataron de diseñar un nuevo lenguaje de programación destinado
a electrodomésticos. La reducida potencia de cálculo y memoria de los
electrodomésticos llevó a desarrollar un lenguaje sencillo capaz de generar
código de tamaño muy reducido.
Debido a la existencia de distintos tipos de CPUs y a los continuos
cambios, era importante conseguir una herramienta independiente del tipo
de CPU utilizada. Desarrollan un código ”neutro”que no depende del tipo
de electrodoméstico, el cual se ejecuta sobre una ”máquina hipotética
o virtual”denominada Java Virtual Machine (JVM). Es la JVM quien
interpreta el código neutro convirtiéndolo a código particular de la CPU
utilizada. Esto permitı́a lo que luego se ha convertido en el principal lema
del lenguaje: ”Write Once, Run Everywhere”.
Al programar en Java no se parte de cero. Cualquier aplicación que
se desarrolle çuelga”(o se apoya, según como se quiera ver) en un gran
número de clases preexistentes. Algunas de ellas las ha podido hacer el
propio usuario, otras pueden ser comerciales, pero siempre hay un número
muy importante de clases que forman parte del propio lenguaje (el API
o Application Programming Interface de Java). Java incorpora muchos
aspectos que en cualquier otro lenguaje son extensiones propiedad de
empresas de software o fabricantes de ordenadores (threads, ejecución
remota, componentes, seguridad, acceso a bases de datos, etc). Por eso es
un lenguaje ideal para aprender la informática moderna, porque incorpora
todos estos conceptos de un modo estándar, mucho más sencillo y claro
que con las citadas extensiones de otros lenguajes. Esto es consecuencia de
haber sido diseñado más recientemente y por un único equipo.
El principal objetivo del lenguaje Java es llegar a ser el ”nexo universal”que conecte a los usuarios con la información, esté ésta situada en
el ordenador local, en un servidor de Web, en una base de datos o en
cualquier otro lugar. La compañı́a Sun describe el lenguaje Java como
”simple, orientado a objetos, distribuido,interpretado, robusto, seguro, de
arquitectura neutra, portable, de altas prestaciones, multitarea y dinámico”.
Los programas desarrollados en Java presentan diversas ventajas frente
a los desarrollados en otros lenguajes como C/C++. La ejecución de
programas en Java tiene muchas posibilidades: ejecución como aplicación
independiente (Stand-alone Application), ejecución como applet, ejecución
como servlet, etc.. Un applet es una aplicación especial que se ejecuta dentro
86
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
5.2. ESTUDIO A TRAVÉS DE UN EJEMPLO.
de un navegador o browser (por ejemplo Netscape Navigator o Internet
Explorer) al cargar una página HTML desde un servidor Web. El applet se
descarga desde el servidor y no requiere instalación en el ordenador donde
se encuentra el browser. Un servlet es una aplicación sin interface gráfica
que se ejecuta en un servidor de Internet. La ejecución como aplicación
independiente es análoga a los programas desarrollados con otros lenguajes.
Además de incorporar la ejecución como Applet, Java permite fácilmente
el desarrollo tanto de arquitecturas clienteservidor como de aplicaciones
distribuidas, consistentes en crear aplicaciones capaces de conectarse a
otros ordenadores y ejecutar tareas en varios ordenadores simultáneamente,
repartiendo por lo tanto el trabajo. Aunque también otros lenguajes de
programación permiten crear aplicaciones de este tipo, Java incorpora en
su propio API estas funcionalidades.
5.2.
Estudio a través de un ejemplo.
Este ejemplo contiene algunas de las caracterı́sticas más importantes de
Java: clases, herencia, interfaces, gráficos, polimorfismo, etc.
5.2.1.
Clase Ejemplo1
En realidad, este programa principal lo único que hace es utilizar la
clase Geometrı́a y sus clases derivadas. Es pues un programa puramente
üsuario”, a pesar de lo cual hay que definirlo dentro de una clase, como
todos los programas en Java.
1. // fichero Ejemplo1.java
2. import java.util.Vector;
3. import java.awt.*;
4. class Ejemplo1 {
5. public static void main(String arg[]) throws InterruptedException
6. {
7. System.out.println(”Empieza main()...”);
8. Circulo c = new Circulo(2.0, 2.0, 4.0);
9. System.out.println(”Diámetro/2 = ”+ c.r );
10. System.out.println(”Punto medio = (”+ c.x + ”,”+ c.y + ”)
r
GVA-ELAI-UPMPFC0074-03
87
CAPÍTULO 5. ESTUDIO DE JAVA.
José Ma Onrubia
unidades.”);
11. Circulo c1 = new Circulo(1.0, 1.0, 2.0);
12. Circulo c2 = new Circulo(0.0, 0.0, 3.0);
13. c = c1.elMayor(c2);
14. System.out.println(”El mayor radio es ”+ c.r + ”.”);
15. c = new Circulo(); // c.r = 0.0;
16. c = Circulo.elMayor(c1, c2);
17. System.out.println(”El mayor radio es ”+ c.r + ”.”);
18. VentanaCerrable ventana =
19. new VentanaCerrable(”Ventana abierta al mundo...”);
20. Vector v = new Vector();
21. CirculoGrafico cg1 = new CirculoGrafico(200, 200, 100, Color.red);
22. CirculoGrafico cg2 = new CirculoGrafico(300, 200, 100, Color.blue);
23. RectanguloGrafico rg = new
24. RectanguloGrafico(50, 50, 450, 350, Color.green);
25. v.addElement(cg1);
26. v.addElement(cg2);
27. v.addElement(rg);
28. PanelDibujo mipanel = new PanelDibujo(v);
29. ventana.add(mipanel);
30. ventana.setSize(500, 400);
31. ventana.setVisible(true);
32. System.out.println(”Termina main()...”);
33. } // fin de main()
34. } // fin de class Ejemplo1
Las sentencias 2 y 3 ”importançlases de los packages de Java, esto
es, hacen posible acceder a dichas clases utilizando nombres cortos. Por
ejemplo, se puede acceder a la clase Vector simplemente con el nombre
Vector en lugar de con el nombre completo java.util.Vector, por haber
introducido la sentencia import de la lı́nea 2.
Un package es una agrupación de clases que tienen una finalidad relacionada. Existe una jerarquı́a de packages que se refleja en nombres compuestos,
separados por un punto (.). Es habitual nombrar los packages con letras
minúsculas (como java.util o java.awt), mientras que los nombres de las
clases suelen empezar siempre por una letra mayúscula (como Vector).
El asterisco (*) de la sentencia 3 indica que se importan todas las clases
del package. Hay un package, llamado java.lang, que se importa siempre
automáticamente. Las clases de java.lang se pueden utilizar directamente,
sin importar el package.
En Java todo son clases: no se puede definir una variable o una función
88
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
5.2. ESTUDIO A TRAVÉS DE UN EJEMPLO.
que no pertenezca a una clase. En este caso, la clase Ejemplo1 tiene como
única finalidad acoger al método main(), que es el programa principal del
ejemplo. Las clases que utiliza main() son mucho más importantes que la
propia clase Ejemplo1.
Las lı́neas 5-33 contienen la definición del programa principal de la
aplicación, que en Java siempre se llama main(). La ejecución siempre
comienza por el programa o método main(). La sentencia 8 (Circulo c =
new Circulo(2.0, 2.0, 4.0);) es muy propia de Java. En ella se crea un objeto
de la clase Circulo, que se define en el apartado 1.3.4. Esta sentencia es
equivalente a las dos sentencias siguientes:
Circulo c;
c = new Circulo(2.0, 2.0, 4.0);
que quizás son más fáciles de explicar.
En primer lugar se crea una referencia llamada c a un objeto de la
clase Circulo. Crear una referencia es como crear un ”nombre”válido para
referirse a un objeto de la clase Circulo. A continuación, con el operador
new se crea el objeto propiamente dicho. Puede verse que el nombre de la
clase va seguido por tres argumentos entre paréntesis. Estos argumentos se
le pasan al constructor de la clase como datos concretos para crear el objeto (en este caso los argumentos son las dos coordenadas del centro y el radio).
Interesa ahora insistir un poco más en la diferencia entre clase y objeto.
La clase Circulo es lo genérico: es el patrón o modelo para crear cı́rculos
concretos. El objeto c es un cı́rculo concreto, con su centro y su radio. De la
clase Circulo se pueden crear tantos objetos como se desee; la clase dice que
cada objeto necesita tres datos (las dos coordenadas del centro y el radio)
que son las variables miembro de la clase. Cada objeto tiene sus propias
copias de las variables miembro, con sus propios valores, distintos de los
demás objetos de la clase. La sentencia 9 (System.out.println(Radio = ”+
c.r + ünidades.”);) imprime por la salida estándar una cadena de texto
que contiene el valor del radio. Esta cadena de texto se compone de tres
subcadenas, unidas mediante el operador de concatenación (+). Obsérvese
cómo se accede al radio del objeto c: el nombre del objeto seguido del
nombre de la variable miembro r, unidos por el operador punto (c.r). El valor numérico del radio se convierte automáticamente en cadena de caracteres.
La sentencia 10 es similar a la 9, imprimiendo las coordenadas del
centro del cı́rculo. La sentencia 13 (c = c1.elMayor(c2);) utiliza el método
r
GVA-ELAI-UPMPFC0074-03
89
CAPÍTULO 5. ESTUDIO DE JAVA.
José Ma Onrubia
elMayor() de la clase Circulo. Este método compara los radios de dos
cı́rculos y devuelve como valor de retorno una referencia al cı́rculo que
tenga mayor radio. Esa referencia se almacena en la referencia previamente
creada c. Un punto importante es que todos los métodos de Java (excepto
los métodos de clase o static) se aplican a un objeto de la clase por medio del
operador punto (c1.elMayor()). El otro objeto (c2) se pasa como argumento
entre paréntesis. Obsérvese la forma .asimétrica”en la que se pasan los
dos argumentos al método elMayor(). De ordinario se llama argumento
implı́cito a c1, mientras que c2 serı́a el argumento explı́cito del método.
La sentencia 14 imprime el resultado de la comparación anterior y la
sentencia 15 crea un nuevo objeto de la clase Circulo guardándolo en la
referencia c. En este caso no se pasan argumentos al constructor de la clase.
Eso quiere decir que deberá utilizar algunos valores ”por defecto”para el
centro y el radio. Esta sentencia anula o borra el resultado de la primera
comparación de radios, de modo que se pueda comprobar el resultado de la
segunda comparación.
La sentencia 16 (c = Circulo.elMayor(c1, c2);) vuelve a utilizar un método
llamado elMayor() para comparar dos cı́rculos: ¿Se trata del mismo método
de la sentencia 13, utilizado de otra forma? No. Se llama de un método
diferente, aunque tenga el mismo nombre. A las funciones o métodos
que son diferentes aunque tienen el mismo nombre se les llama funciones
sobrecargadas (overloaded). Las funciones sobrecargadas se diferencian
por el numero y tipo de sus argumentos. El método de la sentencia 13
tiene un único argumento, mientras que el de la sentencia 16 tiene dos (en
todos los casos objetos de la clase Cı́rculo). En realidad, el método de la
sentencia 16 es un método static (o método de clase), esto es, un método
que no necesita ningún objeto como argumento implı́cito. Los métodos
static suelen ir precedidos por el nombre de la clase y el operador punto
(Java también permite que vayan precedidos por el nombre de cualquier
objeto, pero es considerada una nomenclatura más confusa.). La sentencia
16 es absolutamente equivalente a la sentencia 13, pero el método static de
la sentencia 16 es más ”simétrico”. Las sentencias 17 y 18 no requieren ya
comentarios especiales.
Las sentencias 18-31 tienen que ver con la parte gráfica del ejemplo. En las
lı́neas 18-19 (VentanaCerrable ventana = new VentanaCerrable(”Ventana
abierta al mundo...”);) se crea una ventana para dibujar sobre ella. Una
ventana es un objeto de la clase Frame, del package java.awt. La clase
VentanaCerrable añade a la clase Frame la capacidad de responder a los
eventos que provocan el cierre de una ventana. La cadena que se le pasa
como argumento es el tı́tulo que aparecerá en la ventana. En la sentencia
90
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
5.2. ESTUDIO A TRAVÉS DE UN EJEMPLO.
20 (Vector v = new Vector();) se crea un objeto de la clase Vector (en el
package java.util). La clase Vector permite almacenar referencias a objetos
de distintas clases. En este caso se utilizará para almacenar referencias a
varias figuras geométricas diferentes.
Las siguientes sentencias 21-27 crean elementos gráficos y los incluyen
en el vector v para ser dibujados más tarde en el objeto de la clase
DrawWindow. Los objetos de la clase Circulo creados anteriormente no
eran objetos aptos para ser dibujados, pues sólo tenı́an información del
centro y el radio, y no del color de lı́nea. Las clases RectanguloGrafico y
CirculoGrafico, definidas en los Apartados 1.3.4 y 1.3.7, derivan respectivamente de las clases Rectangulo (Apartado 1.3.3) y Circulo (Apartado 1.3.4),
heredando de dichas clases sus variables miembro y métodos, añadiendo la
información y los métodos necesarios para poder dibujarlos en la pantalla.
En las sentencias 21-22 se definen dos objetos de la clase CirculoGrafico;
a las coordenadas del centro y al radio se une el color de la lı́nea. En
la sentencia 23-24 se define un objeto de la clase RectanguloGrafico,
especificando asimismo un color, además de las coordenadas del vértice
superior izquierdo, y del vértice inferior derecho. En las sentencias 25-27
los objetos gráficos creados se añaden al vector v, utilizando el método
addElement() de la clase Vector.
En la sentencia 28 (PanelDibujo mipanel = new PanelDibujo(v);) se
crea un objeto de la clase PanelDibujo. Por decirlo de alguna manera,
los objetos de dicha clase son paneles, esto es superficies en las que se
puede dibujar. Al constructor de PanelDibujo se le pasa como argumento
el vector v con las referencias a los objetos a dibujar. La sentencia 29 (ventana.add(mipanel);) añade o incluye el panel (la superficie de dibujo) en la
ventana; la sentencia 30 (ventana.setSize(500, 400);) establece el tamaño de
la ventana en pixels; finalmente, la sentencia 31 (ventana.setVisible(true);)
hace visible la ventana creada. ¿Cómo se consigue que se dibuje todo
esto? La clave está en la serie de órdenes que se han ido dando al
computador. La clase PanelDibujo deriva de la clase Container a través
de Panel, y redefine el método paint() de Container. En este método,
se realiza el dibujo de los objetos gráficos creados. El usuario no tiene
que preocuparse de llamar al método paint(), pues se llama de modo
automático cada vez que el sistema operativo tiene alguna razón para
ello (por ejemplo cuando se crea la ventana, cuando se mueve, cuando se
minimiza o maximiza, cuando aparece después de haber estado oculta, etc.).
r
GVA-ELAI-UPMPFC0074-03
91
José Ma Onrubia
CAPÍTULO 5. ESTUDIO DE JAVA.
5.2.2.
Clase Geometrı́a.
En este apartado se describe la clase más importante de esta aplicación.
Es la más importante no en el sentido de lo que hace, sino en el de que
las demás clases ”derivan”de ella, o por decirlo de otra forma, se apoyan o
cuelgan de ella. La Figura 1.2 muestra la jerarquı́a de clases utilizada en este
ejemplo. La clase Geometrı́a es la base de la jerarquı́a. En realidad no es la
base, pues en Java la clase base es siempre la clase Object. Siempre que no
se diga explı́citamente que una clase deriva de otra, deriva implı́citamente
de la clase Object (definida en el package java.lang).
De las clases:
Dibujable
RectanguloGrafico
Rectangulo
Dibujable
CirculoGrafico
Circulo
Geometrı́a
Rectangulo y Circulo derivan respectivamente las clases RectanguloGrafico y CirculoGrafico. En ambos casos está por en medio un elemento un
poco especial donde aparece la palabra Dibujable. En términos de Java,
Dibujable es una interface. Se suele utilizar la nomenclatura de superclase
y subclase para referirse a la clase padre o hija de una clase determinada.
Un aspecto importante a considerar es que no va a haber nunca objetos de
la clase Geometria, es decir ”geometrı́as a secas”. Una clase de la que no va
a haber objetos es una clase abstracta, y como tal puede ser declarada. A
continuación se muestra el fichero Geometrı́a.java en el que se define dicha
clase:
1.
2.
3.
4.
5.
6.
// fichero Geometria.java
public abstract class Geometria {
// clase abstracta que no puede tener objetos
public abstract double perimetro();
public abstract double area();
}
La clase Geometrı́a se declara como public para permitir que sea utilizada
por cualquier otra clase, y como abstract para indicar que no se permite
crear objetos de esta clase. Es caracterı́stico de las clases tener variables y
funciones miembro. La clase Geometrı́a no define ninguna variable miem92
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
5.2. ESTUDIO A TRAVÉS DE UN EJEMPLO.
bro, pero sı́ declara dos métodos: perı́metro() y area(). Ambos métodos se
declaran como public para que puedan ser llamados por otras clases y como
abstract para indicar que no se da ninguna definición, es decir ningún código
para ellos. Interesa entender la diferencia entre declaración (la primera lı́nea
o header del método) y definición (todo el código del método, incluyendo la
primera lı́nea). Se indica también que su valor de retorno -el resultado- va
a ser un double y que no tienen argumentos (obtendrán sus datos a partir
del objeto que se les pase como argumento implı́cito). Es completamente
lógico que no se definan en esta clase los métodos perı́metro() y area():
la forma de calcular un perı́metro o un área es completamente distinta
en un rectángulo y en un cı́rculo, y por tanto estos métodos habrá que
definirlos en las clases Rectángulo y Circulo. En la clase Geometria
lo único que se puede decir es cómo serán dichos métodos, es decir su
nombre, el número y tipo de sus argumentos y el tipo de su valor de retorno.
5.2.3.
Clase Rectángulo.
Según el diagrama de clases de la Figura 1.2 la clase Rectangulo deriva
de Geometria. Esto se indica en la sentencia 2 con la palabra extends (en
negrita en el listado de la clase).
1. // fichero Rectangulo.java
2. public class Rectangulo extends Geometria {
3. // definición de variables miembro de la claes
4. private static int numRectangulos = 0;
5. protected double x1, y1, x2, y2;
6. // constructores de la clase
7. public Rectangulo(double p1x, double p1y, double p2x, double p2y) {
8. x1 = p1x;
9. x2 = p2x;
10. y1 = p1y;
11. y2 = p2y;
12. numRectangulos++;
13. }
14. public Rectangulo(){ this(0, 0, 1.0, 1.0); }
15. // definición de métodos
16. public double perimetro() { return 2.0 * ((x1-x2)+(y1-y2)); }
17. public double area() { return (x1-x2)*(y1-y2); }
18. } // fin de la clase Rectángulo
En la sentencia 4 (private static int numRectangulos = 0;) se define una
r
GVA-ELAI-UPMPFC0074-03
93
CAPÍTULO 5. ESTUDIO DE JAVA.
José Ma Onrubia
variable miembro static. Las variables miembro static se caracterizan por ser
propias de la clase y no de cada objeto. De la variable numRectangulos, que
en la sentencia 4 se inicializa a cero, se mantiene una única copia para toda
la clase. Además esta variable es privada (private), lo cual quiere decir que
sólo las funciones miembro de esta clase tienen permiso para utilizarla. El
declararlas como protected indica que sólo esta clase, las clases que deriven
de ella y las clases del propio package tienen permiso para utilizarlas.
5.2.4.
Clase Circulo.
A continuación se presenta la definición de la clase Circulo, también
derivada de Geometria.
1. // fichero Circulo.java
2. public class Circulo extends Geometria {
3. static int numCirculos = 0;
4. public static final double PI=3.14159265358979323846;
5. public double x, y, r;
6. public Circulo(double x, double y, double r) {
7. this.x=x; this.y=y; this.r=r;
8. numCirculos++;
9. }
10. public Circulo(double r) { this(0.0, 0.0, r); }
11. public Circulo(Circulo c) { this(c.x, c.y, c.r); }
12. public Circulo() { this(0.0, 0.0, 1.0); }
13. public double perimetro() return 2.0 * PI * r; }
14. public double area() { return PI * r * r; }
15. // método de objeto para comparar cı́rculos
16. public Circulo elMayor(Circulo c) {
17. if (this.r>=c.r) return this; else return c;
18. }
19. // método de clase para comparar cı́rculos
20. public static Circulo elMayor(Circulo c, Circulo d) {
21. if (c.r>=d.r) return c; else return d;
22. }
23. } // fin de la clase Circulo
La sentencia 3 (static int numCirculos = 0;) define una variable static o
de clase análoga a la de la clase Rectangulo. En este caso no se ha definido
como private. Cuando no se especifican permisos de acceso (public, private
o protected) se supone la opción por defecto, que es package. Con esta
opción la variable o método correspondiente puede ser utilizada por todas
94
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
5.2. ESTUDIO A TRAVÉS DE UN EJEMPLO.
las clases del package y sólo por ellas. Como en este ejemplo no se ha
definido ningún package, se utiliza el package por defecto que es el directorio
donde están definidas las clases. Ası́ pues, la variable numCirculos podrá ser
utilizada sólo por las clases que estén en el mismo directorio que Circulo.
La sentencia 4 (public static final double PI=3.14159265358979323846;)
define también una variable static, pero contiene una palabra nueva: final.
Una variable final tiene como caracterı́stica el que su valor no puede ser
modificado, o lo que es lo mismo, es una constante. Es muy lógico definir el
número PI como constante, y también es razonable que sea una constante
static de la clase Circulo, de forma que sea compartida por todos los
métodos y objetos que se creen.
La sentencia 6-9 define el constructor general de la clase Circulo. En este
caso tiene una peculiaridad y es que el nombre de los argumentos (x, y,
r) coincide con el nombre de las variables miembro. Esto es un problema,
porque como se verá más adelante los argumentos de un método son
variables locales que sólo son visibles dentro del bloque ... del método, que
se destruyen al salir del bloque y que ocultan otras variables de ámbito más
general que tengan esos mismos nombres. En otras palabras, si en el código
del constructor se utilizan las variables (x, y, r) se está haciendo referencia
a los argumentos del método y no a las variables miembro. La sentencia
7 indica como se resuelve este problema. Para cualquier método no static
de una clase, la palabra this es una referencia al objeto -el argumento
implı́cito- sobre el que se está aplicando el método. De esta forma, this.x se
refiere a la variable miembro, mientras que x es el argumento del constructor.
Las sentencias 10-12 representan otros tres constructores de la clase (métodos sobrecargados), que se diferencian en el número y tipo de argumentos.
Los tres tienen en común el realizar su papel llamando al constructor general
previamente definido, al que se hace referencia con la palabra this (en
este caso el significado de this no es exactamente el del argumento implı́cito).
Las sentencias 13 y 14 definen los métodos perimetro() y area(), declarados como abstract en la clase Geometria, de modo adecuado para los cı́rculos.
Las sentencias 16-18 definen elMayor(), que es un método de objeto para
comparar cı́rculos. Uno de los cı́rculos le llega como argumento implı́cito y
el otro como argumento explı́cito. En la sentencia 17 se ve cómo al radio del
argumento implı́cito se accede en la forma this.r (se podrı́a acceder también
simplemente con r, pues no hay ninguna variable local que la oculte), y al
del argumento explı́cito como c.r, donde c es el nombre del objeto pasado
como argumento. La sentencia return devuelve una referencia al objeto
r
GVA-ELAI-UPMPFC0074-03
95
CAPÍTULO 5. ESTUDIO DE JAVA.
José Ma Onrubia
cuyo radio sea mayor. Cuando éste es el argumento implı́cito se devuelve this.
Las sentencias 20-22 presentan la definición de otro método elMayor(),
que en este caso es un método de clase (definido como static), y por tanto
no tiene argumento implı́cito. Los dos objetos a comparar se deben pasar
como argumentos explı́citos, lo que hace el código muy fácil de entender. Es
importante considerar que en ambos casos lo que se devuelve como valor de
retorno no es el objeto que constituye el mayor cı́rculo, sino una referencia
(un nombre, por decirlo de otra forma).
5.2.5.
Interface Dibujable
.
El diagrama de clases de la Figura 1.2 indica que las clases RectanguloGrafico y CirculoGrafico son el resultado tanto de las clases Rectangulo y
Circulo, de las que derivan, como de la interface Dibujable, que de alguna
manera interviene en el proceso. El concepto de interface es muy importante
en Java. A diferencia de C++, Java no permite herencia múltiple, esto
es, no permite que una clase derive de dos clases distintas heredando de
ambas métodos y variables miembro. La herencia múltiple es fuente de
problemas, pero en muchas ocasiones es una caracterı́stica muy conveniente.
Las interfaces de Java constituyen una alternativa a la herencia múltiple
con importantes ventajas prácticas y de ”estilo de programación”.
Una interface es un conjunto de declaraciones de métodos (sin implementación, es decir, sin definir el código de dichos métodos). La declaración
consta del tipo del valor de retorno y del nombre del método, seguido por
el tipo de los argumentos entre paréntesis. Cuando una clase implementa
una determinada interface, se compromete a dar una definición a todos los
métodos de la interface. En cierta forma una interface se parece a una clase
abstract cuyos métodos son todos abstract. La ventaja de las interfaces
es que no están sometidas a las más rı́gidas normas de las clases; por
ejemplo, una clase no puede heredar de dos clases abstract, pero sı́ puede
implementar varias interfaces.
Una de las ventajas de las interfaces de Java es el establecer pautas
o modos de funcionamiento similares para clases que pueden estar o no
relacionadas mediante herencia. En efecto, todas las clases que implementan
una determinada interface soportan los métodos declarados en la interface
y en este sentido se comportan de modo similar. Las interfaces pueden
también relacionarse mediante mecanismos de herencia, con más flexibilidad que las clases. El fichero Dibujable.java define la interface Dibujable,
96
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
5.2. ESTUDIO A TRAVÉS DE UN EJEMPLO.
mostrada a continuación.
1.
2.
3.
4.
5.
6.
// fichero Dibujable.java
import java.awt.Graphics;
public interface Dibujable {
public void setPosicion(double x, double y);
public void dibujar(Graphics dw);
}
La interface Dibujable está dirigida a incorporar, en las clases que la
implementen, lacapacidad de dibujar sus objetos. El listado muestra la
declaración de los métodos setPosicion() y dibujar(). La declaración de
estos métodos no tiene nada de particular. Como el método dibujar() utiliza
como argumento un objeto de la clase Graphics, es necesario importar dicha
clase. Lo importante es que si las clases RectanguloGrafico y CirculoGrafico
implementan la interface Dibujable sus objetos podrán ser representados
gráficamente en pantalla.
5.2.6.
Clase RectanguloGrafico.
La clase RectanguloGrafico deriva de Rectangulo (lo cual quiere decir
que hereda sus métodos y variables miembro) e implementa la interface
Dibujable (lo cual quiere decir que implementa los métodos declarados en
dicha interface). A continuación se incluye la definición de dicha clase.
1. // Fichero RectanguloGrafico.java
r
GVA-ELAI-UPMPFC0074-03
97
CAPÍTULO 5. ESTUDIO DE JAVA.
José Ma Onrubia
2. import java.awt.Graphics;
3. import java.awt.Color;
4. class RectanguloGrafico extends Rectangulo implements Dibujable {
5. // nueva variable miembro
6. Color color;
7. // constructor
8. public RectanguloGrafico(double x1, double y1, double x2, double y2,
9. Color unColor) {
10. // llamada al constructor de Rectangulo
11. super(x1, y1, x2, y2);
12. this.color = unColor; // en este caso this es opcional
13. }
14. // métodos de la interface Dibujable
15. public void dibujar(Graphics dw) {
16. dw.setColor(color);
17. dw.drawRect((int)x1, (int)y1, (int)(x2-x1), (int)(y2-y1));
18. }
19. public void setPosicion(double x, double y) {
20. ; // método vacı́o, pero necesario de definir
21. }
22. } // fin de la clase RectanguloGrafico
La sentencia 4 indica que RectanguloGrafico deriva de la clase Rectangulo
e implementa la interface Dibujable. Recuérdese que mientras que sólo se
puede derivar de una clase, se pueden implementar varias interfaces, en
cuyo caso se ponen en el encabezamiento de la clase separadas por comas.
La sentencia 6 (Color color;) define una nueva variable miembro que se
suma a las que ya se tienen por herencia. Esta nueva variable es un objeto
de la clase Color.
Las sentencias 14-18 y 19-21 definen los dos métodos declarados por
la interface Dibujable. El método dibujar() recibe como argumento un
objeto dw de la clase Graphics. Esta clase define un contexto para realizar
operaciones gráficas en un panel, tales como el color de las lı́neas, el color de
fondo, el tipo de letra a utilizar en los rótulos, etc. Más adelante se verá con
más detenimiento este concepto. La sentencia 16 (dw.setColor(color);) hace
uso un método de la clase Graphics para determinar el color con el que se
dibujarán las lı́neas a partir de ese momento.
Java obliga a implementar o definir siempre todos los métodos declarados
por la interface, aunque no se vayan a utilizar. Esa es la razón de que las
sentencias 19-21 definan un método vacı́o, que sólo contiene un carácter
98
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
5.2. ESTUDIO A TRAVÉS DE UN EJEMPLO.
punto y coma. Como no se va a utilizar no importa que esté vacı́o, pero
Java obliga a dar una definición o implementación.
5.2.7.
Clase CirculoGrafico.
A continuación se define la clase CirculoGrafico, que deriva de la clase
Circulo e implementa la interface Dibujable.
// fichero CirculoGrafico.java
import java.awt.Graphics;
import java.awt.Color;
public class CirculoGrafico extends Circulo implements Dibujable {
// se heredan las variables y métodos de la clase Circulo
Color color;
// constructor
public CirculoGrafico(double x, double y, double r, Color unColor) {
// llamada al constructor de Circulo
super(x, y, r);
this.color = unColor;
}
// métodos de la interface Dibujable
public void dibujar(Graphics dw) {
dw.setColor(color);
dw.drawOval((int)(x-r),(int)(y-r),(int)(2*r),(int)(2*r));
}
public void setPosicion(double x, double y) {
;
}
} // fin de la clase CirculoGrafico
5.2.8.
Clase PanelDibujo.
La clase que se describe en este apartado es muy importante y quizás
una de las más difı́ciles de entender en este capı́tulo introductorio. La clase
PanelDibujo es muy importante porque es la responsable final de que los
rectángulos y cı́rculos aparezcan dibujados en la pantalla. Esta clase deriva
de la clase Panel, que deriva de Container, que deriva de Component, que
deriva de Object.
Ya se ha comentado que Object es la clase más general de Java. La clase
r
GVA-ELAI-UPMPFC0074-03
99
José Ma Onrubia
CAPÍTULO 5. ESTUDIO DE JAVA.
Component comprende todos los objetos de Java que tienen representación
gráfica, tales como botones, barras de desplazamiento, etc. Los objetos
de la clase Container son objetos gráficos del AWT (Abstract Windows
Toolkit; la librerı́a de clases de Java que permite crear interfaces gráficas de
usuario) capaces de contener otros objetos del AWT. La clase Panel define
los Container más sencillos, capaces de contener otros elementos gráficos
(como otros paneles) y sobre la que se puede dibujar.
La clase PanelDibujo contiene el código que se muestra a continuación.
1. // fichero PanelDibujo.java
2. import java.awt.*;
3. import java.util.Vector;
4. import java.util.Enumeration;
5. public class PanelDibujo extends Panel {
6. // variable miembro
7. private Vector v;
8. // constructor
9. public PanelDibujo(Vector vect) {
10. super(new FlowLayout());
11. this.v = vect;
12. }
13. // redefinición del método paint()
14. public void paint(Graphics g) {
15. Dibujable dib;
16. Enumeration e;
17. e = v.elements();
18. while(e.hasMoreElements()) {
19. dib = (Dibujable)e.nextElement();
20. dib.dibujar(g);
21. }
22. }
23. } // Fin de la clase PanelDibujo
La clase Vector y la interface Enumeration pertenecen al package java.util,
y sirven para tratar colecciones o conjuntos, en este caso conjuntos de
figuras dibujables.
La sentencia 5 indica que la clase PanelDibujo deriva de la clase Panel,
heredando de ésta y de sus superclases Container y Component todas sus
capacidades gráficas.
100
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
5.2. ESTUDIO A TRAVÉS DE UN EJEMPLO.
La sentencia 7 (private Vector v;) crea una variable miembro v que es
una referencia a un objeto de la clase Vector (nótese que no es un objeto,
sino una referencia o un nombre de objeto).
Las sentencias 9-12 definen el constructor de la clase, que recibe como
argumento una referencia vect a un objeto de la clase Vector. En este vector
estarán almacenadas las referencias a los objetos -rectángulos y cı́rculosque van a ser dibujados.
En la sentencia 10 (super(new FlowLayout());) se llama al constructor de
la superclase panel, pasándole como argumento un objeto recién creado de
la clase FlowLayout. Al hablar de construcción de interfaces gráficas con
el AWT, la clase FlowLayout se ocupa de distribuir de una determinada
forma (de izquierda a derecha y de arriba abajo) los componentes gráficos
que se añaden a un çontainer”tal como la clase Panel.
Hay que introducir ahora un aspecto muy importante de Java y, en
general, de la programación orientada a objetos. Tiene que ver con algo
que es conocido con el nombre de Polimorfismo. La idea básica es que
una referencia a un objeto de una determinada clase es capaz de servir de
referencia o de nombre a objetos de cualquiera de sus clases derivadas. Por
ejemplo, es posible en Java hacer lo siguiente:
Geometria geom1, geom2;
geom1 = new RectanguloGrafico(0, 0, 200, 100, Color.red);
geom2 = new CirculoGrafico(200, 200, 100, Color.blue);
Obsérvese que se han creado dos referencias de la clase Geometria que
posteriormente apuntan a objetos de las clases derivadas RectanguloGrafico
y Circulo-Grafico. Sin embargo, hay una cierta limitación en lo que se
puede hacer con las referencias geom1 y geom2. Por ser referencias a la
clase Geometria sólo se pueden utilizar las capacidades definidas en dicha
clase, que se reducen a la utilización de los métodos perimetro() y area().
De la misma forma que se ha visto con la clase base Geometria, en Java es
posible utilizar una referencia del tipo correspondiente a una interface para
manejar objetos de clases que implementan dicha interface. Por ejemplo, es
posible escribir:
r
GVA-ELAI-UPMPFC0074-03
101
CAPÍTULO 5. ESTUDIO DE JAVA.
José Ma Onrubia
Dibujable dib1, dib2;
dib1 = new RectanguloGrafico(0, 0, 200, 100, Color.red);
dib2 = new CirculoGrafico(200, 200, 100, Color.blue);
donde los objetos referidos por dib1 y dib2 pertenecen a las clases RectanguloGrafico y CirculoGrafico, que implementan la interface Dibujable.
También los objetos dib1 y dib2 tienen una limitación: sólo pueden ser
utilizados con los métodos definidos por la interface Dibujable. El poder
utilizar nombres de una superclase o de una interface permite tratar de un
modounificado objetos distintos, aunque pertenecientes a distintas subclases
o bien a clases que implementan dicha interface. Esta es la idea en la que
se basa el polimorfismo.
Ahora ya se está en condiciones de volver al código del método paint(),
definido en las sentencias 14-22 de la clase PanelDibujo. El método paint()
es un método heredado de Container, que a su vez redefine el método
heredado de Component. En la clase PanelDibujo se da una nueva definición
de este método. Una peculiaridad del método paint() es que, por lo general,
el programador no tiene que preocuparse de llamarlo: se encargan de ello
Java y el sistema operativo.
El programador prepara por una parte la ventana y el panel en el que
va a dibujar, y por otra programa en el método paint() las operaciones
gráficas que quiere realizar. El sistema operativo y Java llaman a paint()
cada vez que entienden que la ventana debe ser dibujada o redibujada. El
único argumento de paint() es un objeto g de la clase Graphics que, como
se ha dicho antes, constituye el contexto gráfico (color de las lı́neas, tipo de
letra, etc.) con el que se realizarán las operaciones de dibujo.
La sentencia 15 (Dibujable dib;) crea una referencia de la clase Dibujable,
que como se ha dicho anteriormente, podrá apuntar o contener objetos
de cualquier clase que implemente dicha interface. La sentencia 16 (Enumeration e;) crea una referencia a un objeto de la interface Enumeration
definida en el package java.util. La interface Enumeration proporciona los
métodos hasMoreElements(), que chequea si la colección de elementos que
se está recorriendo tiene más elementos y nextElement(), que devuelve el
siguiente elemento de la colección. Cualquier colección de elementos (tal
como la clase Vector de Java, o como cualquier tipo de lista vinculada
programada por el usuario) puede implementar esta interface, y ser por
102
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
5.2. ESTUDIO A TRAVÉS DE UN EJEMPLO.
tanto utilizada de un modo uniforme.
La sentencia 19 (dib = (Dibujable)e.nextElement();) contiene bastantes
elementos nuevos e importantes. El método e.nextElement() devuelve el
siguiente objeto de la enumeración. En principio este objeto podrı́a ser de
cualquier clase. Los elementos de la clase Vector son referencias de la clase
Object, que es la clase más general de Java, la clase de la que derivan todas
las demás. Esto quiere decir que esas referencias pueden apuntar a objetos
de cualquier clase. El nombre de la interface (Dibujable) entre paréntesis
representa un cast o conversión entre tipos diferentes. En Java como en
C++, la conversión entre variables u objetos de distintas clases es muy
importante. Por ejemplo, (int)3.14 convierte el número double 3.14 en el
entero 3. Evidentemente no todas las conversiones son posibles, pero sı́ lo
son y tienen mucho interés las conversiones entre clases que están en la
misma lı́nea jerárquica (entre sub-clases y super-clases), y entre clases que
implementan la misma interface. Lo que se está diciendo a la referencia
dib con el cast a la interface Dibujable en la sentencia 19, es que el objeto
de la enumeración va a ser tratado exclusivamente con los métodos de
dicha interface. En la sentencia 20 (dib.dibujar(g);) se aplica el método
dibujar() al objeto referenciado por dib, que forma parte de la enumeración
e, obtenida a partir del vector v.
Lo que se acaba de explicar puede parecer un poco complicado, pero es
tı́pico de Java y de la programación orientada a objetos. La ventaja del
método paint() ası́ programado es que es absolutamente general: en ningún
momento se hace referencia a las clases RectanguloGrafico y CirculoGrafico,
cuyos objetos son realmente los que se van a dibujar. Esto permite añadir
nuevas clases tales como TrianguloGrafico, PoligonoGrafico, LineaGrafica,
etc., sin tener que modificar para nada el código anterior: tan sólo es
necesario que dichas clases implementen la interface Dibujable. Esta es una
ventaja no pequeña cuando se trata de crear programas extensibles (que
puedan crecer), flexibles (que se puedan modificar) y reutilizables (que se
puedan incorporar a otras aplicaciones).
5.2.9.
Clase VentanaCerrable.
Es una clase de ütilidad”que mejora algo las caracterı́sticas de la clase
Frame de Java, de la que deriva. La clase Frame estándar tiene una
limitación y es que no responde a las acciones normales en Windows para
cerrar una ventana o una aplicación (por ejemplo, clicar en la cruz de
la esquina superior derecha). En ese caso, para cerrar la aplicación es
necesario recurrir por ejemplo al comando End Task del Task Manager de
Windows NT (que aparece con Ctrl+Alt+Supr). Para evitar esta molestia
r
GVA-ELAI-UPMPFC0074-03
103
CAPÍTULO 5. ESTUDIO DE JAVA.
José Ma Onrubia
se ha creado la clase VentanaCerrable, que deriva de Frame e implementa
la interface WindowListener.
1. // Fichero VentanaCerrable.java
2. import java.awt.*;
3. import java.awt.event.*;
4. class VentanaCerrable extends Frame implements WindowListener {
5. // constructores
6. public VentanaCerrable() {
7. super();
8. }
9. public VentanaCerrable(String title) {
10. super(title);
11. setSize(500,500);
12. addWindowListener(this);
13. }
14. // métodos de la interface WindowsListener
15. public void windowActivated(WindowEvent e) {;}
16. public void windowClosed(WindowEvent e) {;}
17. public void windowClosing(WindowEvent e) {System.exit(0);}
18. public void windowDeactivated(WindowEvent e) {;}
19. public void windowDeiconified(WindowEvent e) {;}
20. public void windowIconified(WindowEvent e) {;}
21. public void windowOpened(WindowEvent e) {;}
22. } // fin de la clase VentanaCerrable
La sentencia 12 (addWindowListener(this);) es muy importante y significativa sobre la forma en que el AWT de Java gestiona los eventos
sobre las ventanas y en general sobre lo que es la interface gráfica de
usuario. Cuando un elemento gráfico -en este caso la ventana- puede recibir
eventos del usuario es necesario indicar quién se va a encargar de procesar
esos eventos. De ordinario al producirse un evento se debe activar un
método determinado que se encarga de procesarlo y realizar las acciones
pertinentes (en este caso cerrar la ventana y la aplicación). La sentencia
12 ejecuta el método addWindowListener() de la clase Frame (que a su
vez lo ha heredado de la clase Window). El argumento que se le pasa
a este método indica qué objeto se va a responsabilizar de gestionar los
eventos que reciba la ventana implementando la interface WindowListener.
En este caso, como el argumento que se le pasa es this, la propia clase
VentanaCerrable debe ocuparse de gestionar los eventos que reciba. Ası́ es,
puesto que dicha clase implementa la interface WindowListener según se ve
104
r
GVA-ELAI-UPMPFC0074-03
5.3. NOMENCLATURA HABITUAL EN LA PROGRAMACIÓN EN
José Ma Onrubia
JAVA.
en la sentencia 4. Puede notarse que como el constructor por defecto de las
sentencias 6-8 no utiliza el método addWindowListener(), si se construye
una VentanaCerrable sin tı́tulo no podrá ser cerrada del modo habitual.
Ası́ se ha hecho deliberadamente en este ejemplo para que el lector lo pueda
comprobar con facilidad.
La interface WindowListener define los siete métodos necesarios para gestionar los siete eventos con los que se puede actuar sobre una ventana. Para
cerrar la ventana sólo es necesario definir el método windowClosing(). Sin
embargo, el implementar una interface obliga siempre a definir todos sus
métodos. Por ello en las sentencias 15-21 todos los métodos están vacı́os
(solamente el punto y coma entre llaves), excepto el que realmente interesa, que llama al método exit() de la clase System. El argumento ”0”indica
terminación normal del programa.
5.3.
Nomenclatura habitual en la programación en
java.
Los nombres de Java son sensibles a las letras mayúsculas y minúsculas.
Ası́, las variables masa, Masa y MASA son consideradas variables completamente diferentes. Las reglas del lenguaje respecto a los nombres de
variables son muy amplias y permiten mucha libertad al programador, pero
es habitual seguir ciertas normas que facilitan la lectura y el mantenimiento
de los programas de ordenador. Se recomienda seguir las siguientes instrucciones:
1. En Java es habitual utilizar nombres con minúsculas, con las excepciones que se indican en los puntos siguientes.
2. Cuando un nombre consta de varias palabras es habitual poner una
a continuación de otra, poniendo con mayúscula la primera letra de
la palabra que sigue a otra (Ejemplos: elMayor(), VentanaCerrable,
RectanguloGrafico, addWindowListener()).
3. Los nombres de clases e interfaces comienzan siempre por mayúscula
(Ejemplos: Geometria, Rectangulo, Dibujable, Graphics, Vector, Enumeration).
4. Los nombres de objetos, los nombres de métodos y variables miembro,
y los nombres de las variables locales de los métodos, comienzan siempre por minúscula (Ejemplos: main(), dibujar(), numRectangulos, x,
y, r).
r
GVA-ELAI-UPMPFC0074-03
105
CAPÍTULO 5. ESTUDIO DE JAVA.
José Ma Onrubia
5. Los nombres de las variables finales, es decir de las constantes, se
definen siempre con mayúsculas (Ejemplo: PI)
5.4.
Estructura general de un programa java.
El anterior ejemplo presenta la estructura habitual de un programa
realizado en cualquier lenguaje orientado a objetos u OOP (Object Oriented Programming), y en particular en el lenguaje Java. Aparece una
clase que contiene el programa principal (aquel que contiene la función
main()) y algunas clases de usuario (las especı́ficas de la aplicación que se
está desarrollando) que son utilizadas por el programa principal.
Los ficheros fuente tienen la extensión *.java, mientras que los ficheros
compilados tienen la extensión *.class. Un fichero fuente (*.java) puede
contener más de una clase, pero sólo una puede ser public. El nombre del
fichero fuente debe coincidir con el de la clase public (con la extensión *.java.
Si la clase no es public, no es necesario que su nombre coincida con el del
fichero. Una clase puede ser public o package (default), pero no private o
protected.
De ordinario una aplicación está constituida por varios ficheros *.class.
Cada clase realiza unas funciones particulares, permitiendo construir
las aplicaciones con gran modularidad e independencia entre clases. La
aplicación se ejecuta por medio del nombre de la clase que contiene la
función main() (sin la extensión *.class). Las clases de Java se agrupan
en packages, que son librerı́as de clases. Si las clases no se definen como
pertenecientes a un package, se utiliza un package por defecto (default) que
es el directorio activo. Los packages se estudian con más detenimiento en
siguientes apartados.
5.4.1.
Concepto de Clase.
Una clase es una agrupación de datos (variables o campos) y de funciones (métodos) que operan sobre esos datos. A estos datos y funciones
pertenecientes a una clase se les denomina variables y métodos o funciones
miembro. La programación orientada a objetos se basa en la programación
de clases. Un programa se construye a partir de un conjunto de clases.
Una vez definida e implementada una clase, es posible declarar elementos
de esta clase de modo similar a como se declaran las variables del lenguaje
(int, double, String, . . . ). Los elementos declarados de una clase se denom106
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
5.4. ESTRUCTURA GENERAL DE UN PROGRAMA JAVA.
inan objetos de la clase. De una única clase se pueden declarar o crear
numerosos objetos. La clase es lo genérico: es el patrón o modelo para crear
objetos. Cada objeto tiene sus propias copias de las variables miembro, con
sus propios valores, en general distintos de los demás objetos de la clase.
Las clases pueden tener variables static, que son propias de la clase y no de
cada objeto.
5.4.2.
Herencia.
La herencia permite que se pueden definir nuevas clases basadas en clases
existentes, lo cual facilita reutilizar código previamente desarrollado. Si una
clase deriva de otra (extends) hereda todas sus variables y métodos. La
clase derivada puede añadir nuevas variables y métodos y/o redefinir las
variables y métodos heredados.
En Java, a diferencia de otros lenguajes orientados a objetos, una clase
sólo puede derivar de una única clase, con lo cual no es posible realizar
herencia múltiple en base a clases. Sin embargo es posible ”simular”la
herencia múltiple en base a las interfaces.
5.4.3.
Concepto de Interface.
Una interface es un conjunto de declaraciones de funciones. Si una clase
implementa (implements) una interface, debe definir todas las funciones
especificadas por la interface. Una clase puede implementar más de una
interface, representando una forma alternativa de la herencia múltiple.
Una interface puede derivar de otra o incluso de varias interfaces, en cuyo
caso incorpora todos los métodos de las interfaces de las que deriva.
5.4.4.
Concepto de Package.
Un package es una agrupación de clases. Existen una serie de packages incluidos en el lenguaje (ver jerarquı́a de clases que aparece en el
API de Java). Además el usuario puede crear sus propios packages. Lo
habitual es juntar en packages las clases que estén relacionadas. Todas
las clases que formen parte de un package deben estar en el mismo directorio.
r
GVA-ELAI-UPMPFC0074-03
107
José Ma Onrubia
CAPÍTULO 5. ESTUDIO DE JAVA.
5.4.5.
La jerarquı́a de clases de Java (API).
Durante la generación de código en Java, es recomendable y casi necesario
tener siempre a la vista la documentación on-line del API de Java . En
dicha documentación es posible ver tanto la jerarquı́a de clases, es decir
la relación de herencia entre clases, como la información de los distintos
packages que componen las librerı́as base de Java.
Hay que resaltar el hecho de que todas las clases en Java son derivadas de
la clase java.lang.Object, por lo que heredan todos los métodos y variables
de ésta.
108
r
GVA-ELAI-UPMPFC0074-03
Capı́tulo 6
Desarrollo de nuestra
aplicación mediante JDT,
JDK 1.4.1 y JBuilder7.
6.1.
Introducción.
Una vez elegidas las librerı́as JDT y hecho un estudio de Java, se está listo
para comenzar a crear nuestra aplicación DICOM.
El primer paso que se tiene que dar es la elección del entorno de desarrollo
a utilizar. La disyuntiva que aparece es el uso de JBuilder o de Visual J++;
pero la elección está casi tomada desde un principio a favor de JBuilder
de Borland debido a lo mucho más completo, especı́fico y con muchas más
prestaciones que VJ++.
Por lo tanto nos encontramos con un entorno de desarrollo llamado
JBuilder (en nuestro caso la versión 7.0 Enterprise), con unas librerı́as
de DICOM llamadas JDT y con las propias librerı́as Java, JDK (1.4.1),
mediante las cuales se va a implementar nuestra aplicación DICOM.
Paso a paso se va a ver la progresión seguida para este proceso de creación
de la aplicación, cuyo orden podrı́a ser el siguiente:
Uso de JBuilder 7.0
Uso de librerı́as JDK 1.4.1
Uso de librerı́as JDK y JDT en JBuilder
Implementación conjunta.
109
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
6.2.
Uso de JBuilder 7.0
6.2.1.
Introducción.
En esta sección se van a ver los aspectos más importantes a la hora
de crear una aplicación (interfaz de usuario) mediante este programa de
desarrollo.
6.2.2.
Instalación de JBuilder.
Es un proceso muy sencillo en el cual hemos tenido algunas peculiaridades.
Pasos para la instalación:
1. Ir a la página web de sun (http://www.borland.com/products/ downloads/download builder.html) y descagar la versión de JBuilder deseada; en nuestro caso JBuilder 7.0 Enterprise.
2. Pedir via email un archivo de activación necesario para poder trabajar
con el programa.
3. Ejecutar JBuilder y cuando pide el archivo de activación indicarle la
ruta de éste.
4. Cambiar el archivo localizado en .../JBuilder7/bin jbuilder.jar y sustituirlo por el proporcionado para que la licencia dure en vez de un mes,
unos cuantos dı́as más. En este momento es posible trabajar con el
programa sin preocuparnos de problemas de tiempo con la licencia.
6.2.3.
Creación de una aplicación JBuilder.
Se va a crear un simple editor de texto para ver cómo realizar una
aplicación. El estudio de este ejemplo proporciona una base espléndida
para, a partir de éste, tener las nociones básicas en JBuilder y poder
avanzar rápida y fácilmente en la creación de una interfaz de usuario.
Pasos:
Paso 1: Creación de un proyecto.
Para crear un proyecto se usa el asistente para proyectos y el asistente
para aplicaciones, lo que acelera este proceso de creación, de esta forma:
110
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
6.2. USO DE JBUILDER 7.0
1. Elija Archivo—Nuevo proyecto para iniciar el Asistente para proyectos.
2. Realice los siguientes cambios en el Paso 1:
Nombre: Editor de texto
Tipo (tipo de archivo): .jpx
Seleccione la opción Crear archivo de notas del proyecto. Al seleccionar esta opción, el Asistente para proyectos crea un archivo
HTML para las notas del proyecto y lo añade al mismo.
3. Acepte todas las demás opciones por defecto en el Paso 1, 2 y 3.
Figura 6.1: Asistente para proyectos: paso 1
Una vez creado nuestro proyecto podemos pasar a crear nuestra aplicación
dentro de él mediante el asistente para aplicaciones:
1. Abra la galerı́a de objetos seleccionando Archivo—Nuevo.
2. Haga doble clic en el en el icono Aplicación para abrir el Asistente
para aplicaciones.
r
GVA-ELAI-UPMPFC0074-03
111
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
3. Cambie el nombre de clase de la aplicación en el Paso 1.
4. Pulse Siguiente para ir al Paso 2 del Asistente para proyectos.
5. Cambie el nombre y el tı́tulo de la clase de marco en el Paso 2
6. Seleccione todas las opciones del Paso 2. El asistente genera automáticamente el código correspondiente a las opciones seleccionadas.
(Fı́jese en el significado de cada opción según las va marcando).
7. Haga clic en el botón Finalizar. El Asistente para aplicaciones añade
al proyecto un .java y archivos de imagen.
8. Guarde el proyecto utilizando Archivo—Guardar proyecto.
9. Pulse la pestaña Diseño del archivo abierto, TextEditFrame.java. La
pestaña Diseño, ubicada en la parte inferior de la ventana del Visualizador de aplicaciones, abre el diseñador de interfaces de usuario.
Observe estos cambios en el IDE de JBuilder:
En el panel de contenido aparece el diseñador de interfaces.
El árbol de componentes aparece en el panel de estructura.
El Inspector aparece a la derecha del diseñador.
112
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
6.2. USO DE JBUILDER 7.0
Figura 6.2: Partes de aplicación.
Paso 2: Añadir un área de texto.
En este paso se crea un área de texto que rellena por completo el marco
de la interfaz de usuario entre la barra de menús por encima y la barra
de estado por debajo. Para lograrlo, el gestor de diseños del contenedor
principal de la interfaz de usuario debe utilizar BorderLayout. Como
consecuencia de la utilización del Asistente para aplicaciones, el principal
contenedor de esta interfaz de usuario, que aparece como this en el árbol
de componentes, contiene un JPanel denominado contentPane que ya se ha
cambiado a BorderLayout. Lo único que hay que hacer ahora es añadir los
componentes del área de texto a contentPane.
Para ello, se añadirá un panel de desplazamiento en el contentPane
y después se colocará un componente de área de texto dentro del panel
de desplazamiento. El panel de desplazamiento proporciona barras de
desplazamiento al área de texto.
r
GVA-ELAI-UPMPFC0074-03
113
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
1. Haga clic en la pestaña TextEditFrame del editor, y a continuación
seleccione la pestaña Diseño.
2. Haga clic en el componente contentPane del árbol de componentes
para seleccionarlo, como se muestra a continuación.
Figura 6.3: contentPane
3. Pulse la pestaña Contenedores Swing en la paleta de componentes y
seleccione el componente JScrollPane.
Figura 6.4: JScrollPane
4. Haga clic en el centro de contentPane del diseñador de interfaces. Esto
coloca el componente JScrollPane en el panel de contenido y deberı́a
darle una restricción de centro BorderLayout, haciendo que ocupe completamente el área situada entre la barra de herramientas y la barra
de desplazamiento. Si no lo consigue, seleccione Edición—Deshacer e
inténtelo de nuevo.
5. Seleccione el nuevo componente jScrollPane1 en el árbol de componentes.
114
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
6.2. USO DE JBUILDER 7.0
6. Fı́jese en el valor de la propiedad constraints del Inspector y compruebe
que se le está asignando el valor Center. Si no es ası́, seleccione Center
en la lista desplegable.
Figura 6.5: constraints
7. Pulse la pestaña Swing en la paleta y seleccione el componente
JTextArea.
Figura 6.6: JTextArea
8. Haga clic sobre el componente jScrollPane1 en el árbol de componentes
o arrástrelo al diseñador de interfaces para colocar JTextArea en el
panel de desplazamiento.
9. En el Inspector, haga clic con el botón derecho sobre la propiedad text
y seleccione Borrar el valor de la propiedad para eliminar jTextArea1
del área de texto.
r
GVA-ELAI-UPMPFC0074-03
115
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
Figura 6.7: text
10. Por último, debe definir algunas propiedades en jTextArea1 para que
ajuste automáticamente las lı́neas de texto y lo haga en los espacios
entre palabras. En el Inspector, asigne los siguientes valores:
lineWrap = true
wrapStyleWord = true
background = white
A continuación, compile el programa y ejecútelo para ver qué aspecto
ofrece.
1. Seleccione Proyecto—Ejecutar Make del proyecto en el menú. Esto
compila todos los archivos del proyecto y crea un archivo TextEditClass.class y un TextEditFrame.class en una carpeta de clases dentro
de la carpeta de proyectos. Deberı́a compilarse sin errores.
2. Haga clic en el botón Ejecutar en la barra de herramientas de JBuilder
o seleccione Ejecutar—Ejecutar proyecto en el menú. Ahora la interfaz
de usuario ofrecerá un aspecto similar al siguiente:
116
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
6.2. USO DE JBUILDER 7.0
Figura 6.8: Ejecutado
3. En la aplicación ”Editor de texto”, seleccione Archivo—Salir para cerrar la ventana de ejecución.
Paso 3: Crear menús.
En este paso se van a crear estos menús:
Figura 6.9: Menús
1. Haga clic en la pestaña Diseño de TextEditFrame.java si aún no está seleccionada.
2. Haga doble clic sobre jMenuBar1 en la carpeta Menu del árbol de componentes para abrir el diseñador de menús. (También puede seleccionar
un elemento de menú del árbol de componentes y pulsar Intro.)
3. Seleccione el elemento de menú Archivo—Salir en el diseñador de
menús o jMenuFileExit en el árbol de componentes. El diseñador de
menús resaltará el elemento seleccionado.
4. Haga clic en el botón Insertar elemento de menú de la barra de herramientas del diseñador de menús, o pulse la tecla Insert del teclado.
Encima de Salir se introduce un nuevo elemento de menú resaltado y
vacı́o.
r
GVA-ELAI-UPMPFC0074-03
117
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
5. Escriba Nuevo en el área resaltada.
6. Pulse Flecha abajo para aceptar la nueva entrada y baje al siguiente
elemento (en este caso, el elemento de menú Salir).
7. Haga clic con el botón derecho en Salir y seleccione Insertar elemento de menú en el menú contextual. Escriba Abrir. Nota: También se
puede acceder a todas las acciones de la barra de herramientas desde
el menú emergente que aparece al hacer clic con el botón derecho.
8. De la misma forma, añada los elementos de menú Guardar y Guardar
como.
9. Seleccione Salir y haga clic en el botón Separador de la barra de herramientas para insertar una barra. El menú Archivo ya está terminado.
10. Haga clic con el botón derecho en la barra principal de menús y seleccione Insertar menú. Ası́ se crea un menú entre los menús Archivo y
Ayuda. Escriba Edición como nombre de este menú.
11. Pulse Intro para descender hacia la siguiente entrada vacı́a. No es necesario pulsar Insert aquı́ porque este menú no contiene ningún elemento
después de la entrada actual. Sugerencia: Para borrar una entrada, selecciónela y haga clic en el botón Borrar de la barra de herramientas,
o pulse la tecla Supr dos veces. La primera vez que se pulsa la tecla
Supr se borra el texto de la entrada. La segunda vez elimina la entrada
del menú.
12. Prosiga con la construcción del menú Edición tal y como se indica en
la siguiente imagen, añadiendo tres elementos: Fuente (JBuilder SE y
Enterprise), Color de texto y Color de fondo. Si alguna entrada tiene
una longitud superior al área de edición, el texto se desplazará automáticamente a medida que escriba. Cuando pulse Intro, el diseñador
de menús ajustará el ancho del menú para mostrar el elemento más
largo de la lista.
13. Cierre el diseñador de menús con un doble clic en cualquier componente de la sección de la interfaz de usuario del árbol de componentes.
Esto hará que el panel de contenido cambie al diseñador de interfaces.
14. Guarde el archivo y ejecute la aplicación. Ahora la interfaz de usuario
ofrecerá un aspecto similar al siguiente:
118
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
6.2. USO DE JBUILDER 7.0
Figura 6.10: Editor
Debe poder experimentar con la interfaz de usuario y escribir texto en
el área de texto, pero los botones no funcionarán todavı́a aunque sı́ lo
harán los menús Archivo—Salir y Ayuda—Acerca de.
Paso 4: Añadir un cuadro de diálogo Selector de fuentes.
Comencemos a enlazar los sucesos de menú, empezando con el elemento
de menú Edición—Fuente que es el que va a mostrar el cuadro de diálogo
Selector de fuentes.
En primer lugar, para poder utilizar esta opción de menú, debe añadir un
componente cuadro de diálogo Selector de fuentes a la clase TextEditFrame:
1. Abra TextEditFrame.java en el diseñador de interfaces.
2. Seleccione la pestaña Más dbSwing de la paleta de componentes y haga
clic en el componente FontChooser .
3. Haga clic en cualquier lugar del árbol de componentes o en el diseñador
de interfaces, para añadir el FontChooser al diseño. Esto situará el
componente dentro de la clase como fontChooser1 y lo mostrará en la
carpeta Otros del árbol de componentes.
Sólo verá el componente cuadro de diálogo en el árbol de componentes,
no en el diseñador de interfaces.
Creación de un suceso para lanzar el Selector de fuentes
Creación de un suceso para el elemento de menú Edición—Fuente, que
lanzará el Selector de fuentes:
r
GVA-ELAI-UPMPFC0074-03
119
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
1. Seleccione el elemento de menú Edición—Fuente en el árbol de componentes. Deberı́a ser jMenuItem5 (en el segundo nodo de menú, llamado jMenu1.) Obsérve que la propiedad text para este elemento
de menú del Inspector dice ”Fuente”. No importa si su elemento de
menú Fuente tiene un número diferente a éste. Pero asegúrese de seleccionar el correspondiente al menú Fuente.
2. Haga clic en la pestaña sucesos en el Inspector, y haga doble clic en
el campo de valor (la segunda columna) del suceso actionPerformed.
En los menús, botones y otros muchos componentes de la interfaz de
usuario de Java, actionPerformed es el suceso principal de usuario, que
deberı́a capturar para responder al usuario cuando utiliza el menú o el
botón. El nombre del método de tratamiento de sucesos aparece en el
campo de valor. Si el método no existe todavı́a, esta operación muestra
el nombre propuesto por defecto para el nuevo método de gestión del
suceso. Para este nuevo manejador de sucesos, el nombre propuesto es
jMenuItem5 actionPerformed.
Figura 6.11: actionPerformed
3. Haga doble clic en el valor de este suceso, o pulse Intro para crear el
suceso.
Si el método de tratamiento del suceso es nuevo, esta operación generará un stub vacı́o para el método en el código fuente. Independientemente de si el método es nuevo o ya existe, el foco de ventana
cambiará a código fuente en el editor y colocará el cursor dentro del
método de tratamiento de sucesos. En el caso de un método nuevo de
tratamiento de sucesos, como es el caso, verá que la sección principal
del método no contiene todavı́a código alguno.
4. Escriba esta lı́nea de código en el cuerpo de este nuevo método vacı́o
(entre las llaves de apertura y cierre): fontChooser1.showDialog();
120
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
6.2. USO DE JBUILDER 7.0
Ahora el método deberı́a parecerse a éste:
void jMenuItem5 actionPerformed(ActionEvent e)
{
fontChooser1.showDialog();
}
5. Guarde y ejecute la aplicación. El elemento de menú Edición—Fuente
deberı́a abrir el cuadro de diálogo Selector de fuentes. Si no, compruebe
que la propiedad frame tiene el valor this. Aunque intente cambiar la
fuente, no sucederá nada. Esto se debe a que no se utiliza el resultado
del FontChooser para cambiar el texto del área de edición. Esto será lo
siguiente que hagamos.
6. Cierre la aplicación ”EditorDeTexto”.
Paso 5: Vinculación de sucesos de elemento de menú al cuadro de
diálogo Selector de fuentes.
Vamos a utilizar el cuadro de diálogo Selector de fuentes para modificar
la propiedad font de textArea1.
1. Haga clic en la pestaña Fuente y seleccione el método de
tratamiento del suceso del elemento de menú Fuente ( jMenuItem5 actionPerformed(ActionEvent e))) recién creado.
r
GVA-ELAI-UPMPFC0074-03
121
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
Figura 6.12: jMenu
2. Introduzca este código en el método de tratamiento de sucesos
para el elemento de menú Fuente (jMenuItem5), entre las llaves
de apertura y cierre, asegurándose de reemplazar el código antiguo
fontChooser1.showDialog();:
// Gestiona el elemento de menú ”Edición Fuente”
// Obtiene la fuente existente en el área de texto
// y la lleva al Selector de fuente antes de mostrarlo
// para que se modifique la fuente
// que ya existe
fontChooser1.setSelectedFont(jTextArea1.getFont());
// Obtiene la nueva fuente del Selector de fuentes
// Comprueba primero el valor devuelto por showDialog() para
// ver si el usuario pulsó Aceptar.
if (fontChooser1.showDialog()) {
// Asigna a la fuente de jTextArea1 el valor
// seleccionado por el usuario antes de pulsar Aceptar
jTextArea1.setFont(fontChooser1.getSelectedFont());
} //pinta el menú de nuevo una vez que el elemento se ha seleccionado
this.repaint();
//Vuelve a dibujar el texto correctamente si hay texto selecionado al
122
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
6.2. USO DE JBUILDER 7.0
cambiar la fuente.
jTextArea1.repaint();
3. Guarde y ejecute la aplicación y escriba algo en el área de texto.
4. Seleccione el texto y utilice el elemento de menú Edición—Fuente para
cambiar la fuente. En esta aplicación, se cambia la fuente de la totalidad del área de texto (no solamente del texto seleccionado). No espere
que la configuración de fuentes se mantenga. No introduciremos código
para activar esa caracterı́stica.
5. Cierre la aplicación ”EditorDeTexto”.
Paso 6: Vinculación de sucesos de elementos de menú a JColorChooser.
A continuación se crean los sucesos de menú Edición—Color de texto
y Edición—Color de fondo y se los vincula con el cuadro de diálogo
JColorChooser de Swing.
Al no necesitar asignar valores a ninguna de las propiedades de JColorChooseren el diseñador, no es preciso añadirlo a la interfaz de usuario
del diseñador. Puede llamarlo directamente desde el manejador del suceso
actionPerformed() de un elemento de menú del siguiente modo:
1. Vuelva al diseñador de TextEditFrame.java.
2. Seleccione el segundo elemento de menú del árbol de componentes en
Edición (jMenuItem6) que tiene escrito Çolor de texto”en la propiedad
actionCommand.
3. Seleccione la pestaña Sucesos en el Inspector y haga clic tres veces en
el suceso actionPerformed() para crear el manejador del suceso:
void jMenuItem6 actionPerformed(ActionEvent e) {
}
4. Añada el código siguiente en el stub del manejador del suceso
r
GVA-ELAI-UPMPFC0074-03
123
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
(incluyendo los comentarios si lo desea):
//Gestiona el elemento de menú Çolor de texto”
Color color = JColorChooser.showDialog(this,Çolor de texto”,
jTextArea1.getForeground());
if (color != null) {
jTextArea1.setForeground(color);
}
//pinta el menú de nuevo una vez que el elemento se ha seleccionado
this.repaint();
5. Vuelva al diseñador.
6. Seleccione el tercer elemento de menú en el árbol de componentes, en
Edición (menuItem7), que debe tener la etiqueta Çolor de fondo”en la
propiedad actionCommand. Cree un suceso actionPerformed () para
él, tal como hizo con jMenuItem6.
7. Inserte el siguiente código en el suceso actionPerformed() de jMenuItem7:
// Gestiona el elemento de menú Çolor de fondo”
Color color = JColorChooser.showDialog(this,Çolor de fondo”,
jTextArea1.getBackground());
if (color != null) {
jTextArea1.setBackground(color);
}
//pinta el menú de nuevo una vez que el elemento se ha seleccionado
this.repaint();
8. Guarde el archivo, compile y ejecute la aplicación. Escriba texto y
haga pruebas con los colores de primer plano y de fondo. La aplicación
ofrecerá el siguiente aspecto, si elige texto blanco con fondo negro:
124
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
6.2. USO DE JBUILDER 7.0
Figura 6.13: editor en negro
9. Cierre la aplicación ”EditorDeTexto”.
Paso 7: Adición de un manejador a un suceso de menú para borrar
el área de texto.
Vamos a capturar el elemento de menú Archivo—Nuevo con un manejador
que borra el contenido del área de texto.
1. Vuelva al diseñador.
2. Seleccione el elemento de menú Archivo—Nuevo del árbol de componentes (jMenuItem1).
3. Cree un suceso actionPerformed() e introduzca en él este código:
// Gestiona el elemento de menú Archivo—Nuevo.
// Borra el texto del área del texto.
jTextArea1.setText();
4. Guarde y ejecute la aplicación, escriba algo en el área de texto y vea
qué sucede al seleccionar Archivo—Nuevo. Deberı́a borrar el contenido.
Observe que no pregunta si desea guardar el archivo antes. Para poder
tratar este aspecto, tendrá que configurar la infraestructura para la
lectura y escritura de archivos de texto, para controlar si el archivo ha
cambiado y necesita guardarse, etcétera. Comenzaremos la utilización
de archivos en el paso siguiente.
5. Cierre la aplicación ”EditorDeTexto”.
r
GVA-ELAI-UPMPFC0074-03
125
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
Paso 8: Añadir un cuadro de diálogo selector de archivos.
Vamos a enlazar el elemento de menú Archivo—Abrir con un manejador
de un suceso que presenta al usuario un JFileChooser (cuadro de diálogo
para abrir archivos) para archivos de texto. Cuando el usuario selecciona
un archivo y hace clic en Aceptar el manejador del suceso abre el archivo
de texto y coloca su contenido dentro de JTextArea.
1. Vuelva al diseñador y seleccione el componente JFileChooser de la
ficha Swing Containers de la paleta de componentes.
2. Haga clic en la carpeta IU del árbol de componentes para colocar el
componente. (Si hace clic en el diseñador de interfaces, el componente
se colocará en una sección equivocada del árbol.)
3. Seleccione el elemento de menú Archivo—Abrir en el árbol de componentes (jMenuItem2).
4. Cree un suceso actionPerformed() e introduzca este código:
// Gestionar el elemento de menú Archivo—Abrir.
//Utilizar la versión OPEN del cuadro de diálogo, comprobar el valor
devuelto de Aceptar/Cancelar
if
(JFileChooser.APPROVE OPTION
==
jFileChooser1.showOpenDialog(this)) {
// Muestra el nombre del directorio y archivos abiertos en la barra de
estado.
statusBar.setText(.Abierto
”+jFileChooser1.getSelectedFile().getPath());
// El código debe ir aquı́ para cargar realmente el texto
// en el TextArea.
}
5. Salvar y ejecutar la aplicación. En el menú Archivo—Abrir, seleccione
un archivo y pulse aceptar. Debe aparecer el nombre del archivo y
el directorio completo en la lı́nea de estado en la parte inferior de la
ventana. Sin embargo, el área de texto seguirá vacı́a. Nos ocuparemos
de ello en el siguiente paso.
6. Cierre la aplicación ”EditorDeTexto.antes de continuar.
126
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
6.2. USO DE JBUILDER 7.0
Paso 9: Añadir código para leer texto de un archivo.
Posteriormente, vamos a añadir código para leer el texto del archivo
seleccionado por el usuario y ponerlo en el JTextArea.
En primer lugar, habrá que añadir un nuevo método a la clase para
realizar la operación de apertura del archivo. Este método se llamará openFile():
1. Cambie el editor a TextEditFrame.java e introduzca el siguiente
método openFile(). Puede ponerlo en cualquier lugar de la clase
(fuera de otros métodos). Un buen lugar para ubicarlo es justo
después del código del método jbInit() y justo antes del suceso
jMenuFileExit actionPerformed().
// Abrir el archivo con nombre; lee el texto del archivo al jTextArea1;
informar a la barra de estado.
void openFile(String fileName)
{
try
{
// Abrir un archivo con nombre.
File file = new File(fileName);
// Obtener el tamaño del archivo abierto.
int size = (int)file.length();
// Asignar cero a un contador para realizar un recuento de
// los caracteres que se han leı́do del archivo.
int chars read = 0;
// Crear un lector de entrada basado en el archivo, para leer los
datos.
// FileReader gestiona las conversiones de código de caracteres
internacionales.
FileReader in = new FileReader(file);
// Crea una matriz de caracteres del tamaño del archivo,
// para utilizarla como búfer de datos, en el que leer
// los datos del texto.
char[] data = new char[size];
r
GVA-ELAI-UPMPFC0074-03
127
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
// Leer todos los caracteres disponibles en el búfer.
while(in.ready())
// Incrementar el recuento de cada carácter leı́do,
// y acumularlos en el búfer de datos.
chars read += in.read(data, chars read, size - chars read);
}
in.close();
// Crear una cadena temporal que contenga los datos, // y asignar la cadena a JTextArea. jTextArea1.setText(new String(data, 0,
chars read));
// Muestra el nombre del directorio y archivos abiertos en la barra de
estado. statusBar.setText(.Abierto ”+fileName); } catch (IOException
e) { statusBar.setText(”Error al abrir ”+fileName); }
2. Añada la importación siguiente a la lista de importaciones de la parte
superior del archivo:
import java.io.*;
3. Haga clic en el manejador del suceso de Archivo—Abrir (jMenuItem2 actionPerformed(ActionEvent)) del panel de estructura para
buscarlo rápidamente en el código fuente.
4. Reemplace el código fuente en el manejador del suceso de Archivo—Abrir if() que contenı́a previamente:
// Muestra el nombre del directorio y archivos abiertos en la barra de
estado.
statusBar.setText(.Abierto
”+jFileChooser1.getSelectedFile().getPath());
// El código debe ir aquı́ para cargar realmente el texto
// desde el archivo al JTextArea.
con este nuevo método openFile(), empleando el nombre de directorio
y archivo concatenados.
// Llamar a openFile para intentar cargar el texto desde el archivo al
128
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
6.2. USO DE JBUILDER 7.0
JTextArea
openFile(jFileChooser1.getSelectedFile().getPath());
//pinta el menú de nuevo una vez que el elemento se ha seleccionado
this.repaint();
5. Pruebe el programa ahora y vea si funciona. Guarde y ejecute el programa, y abra un archivo de texto en el editor. El editor de textos
debe tener algún contenido.
6. Cierre la aplicación ”EditorDeTexto”.
Paso 10: Adición de código a los elementos de menú para guardar
un archivo
Ahora se precisa un código que vuelva a grabar el archivo a disco cuando
se seleccione Archivo—Guardar y Archivo—Guardar como.
Para ello, es necesario añadir una variable de instancia String para
almacenar el nombre del archivo abierto, además de añadir métodos para
escribir de nuevo el texto en este y en otros archivos.
1. Haga clic en jFileChooser1 en el panel de estructura. Esto le llevará a
la última entrada de la lista de declaraciones de variables de instancia
(dado que jFileChooser1 fue la última declaración realizada).
2. Añada las siguientes declaraciones al final de la lista después de jFileChooser1:
String currFileName = null; //Vı́a completa con nombre de archivo.
null significa nuevo / sin tı́tulo.
boolean dirty = false; // True significa texto modificado.
3. Haga clic en el método openFile(String fileName) del panel de estructura para buscarlo rápidamente en el código fuente. Sitúe el cursor en
el método, a continuación de la lı́nea siguiente que lee el archivo en
JTextArea:
jTextArea1.setText(new String(data, 0, chars read));
4. Inserte el siguiente código en esta posición:
// Almacenar en caché el nombre de archivo abierto actualmente para
r
GVA-ELAI-UPMPFC0074-03
129
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
utilizarlo al guardar... this.currFileName = fileName;
// ...y marcar la sesión de modificación como borrada
this.dirty = false;
5. Cree un método saveFile() al que pueda llamar desde el manejador
del suceso de Archivo—Guardar. Puede colocarlo justo después del
método openFile(). Este método escribe el nombre de archivo en la
barra de estado al guardar.
// Guardar archivo actual; gestionar los que no tienen nombre de
archivo; informar a la barra de estado.
boolean saveFile() {
//Gestionar donde aún no exista nombre de archivo.
if (currFileName == null) {
return saveAsFile();
}
try
{
// Abrir el archivo del nombre actual.
File file = new File (currFileName);
// Crear un escritor de salida que escribirá ese archivo.
// FileWriter gestiona las conversiones de códigos de caracteres
internacionales.
FileWriter out = new FileWriter(file);
String text = jTextArea1.getText();
out.write(text);
out.close();
this.dirty = false;
// Muestra el nombre del directorio y archivos abiertos en la barra de
estado.
statusBar.setText(”Error al guardar ”+currFileName);
return true;
}
catch(IOException e) {
statusBar.setText(”Error al guardar ”+currFileName);
}
return false;
}
130
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
6.2. USO DE JBUILDER 7.0
6. Cree el método saveAsFile() al que se llama desde saveFile() si
no existe nombre de archivo actual. Lo utilizará también desde el
menú Archivo—Guardar como. Añada el código siguiente justo a
continuación del método saveFile():
// Guardar el archivo actual, preguntando al usuario el nuevo nombre
de destino.
// Informar a la barra de estado.
boolean saveAsFile() {
//Utilizar la versión SAVE del cuadro de diálogo, comprobar el valor
devuelto de Aceptar/Cancelar
if
(JFileChooser.APPROVE OPTION
==
jFileChooser1.showSaveDialog(this)) {
// Asignar al nombre de archivo actual la selección del usuario
// a continuación realizar un saveFile normal
currFileName = jFileChooser1.getSelectedFile().getPath();
//pinta el menú de nuevo una vez que el elemento se ha seleccionado
this.repaint();
return saveFile();
}
else {
this.repaint();
return false;
}
}
7. Vuelva al diseñador y cree un manejador del suceso actionPerformed()
para el elemento de menú Archivo—Guardar (jMenuItem3). Inserte
el siguiente código:
//Gestionar el elemento de menú Archivo—Guardar.
saveFile();
8. Cree un manejador de sucesos actionPerformed() para el elemento de
menú Archivo—Guardar como (jMenuItem4) e introduzca este código:
//Gestionar el elemento de menú Archivo—Guardar como.
saveAsFile();
9. Guarde y compile el archivo. Ejecútelo e intente guardar texto en un
r
GVA-ELAI-UPMPFC0074-03
131
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
archivo.
10. Cierre la aplicación ”EditorDeTexto”.
Con estos pasos se tiene un conocimiento básico de cómo crear un GUI
(graphical user interface) que es nuestro punto de base para construir
nuestra aplicación DICOM.
6.3.
Uso de librerı́as JDK 1.4.1
6.3.1.
Introducción e instalación.
Para poder realizar aplicaciones Java, se necesitan las librerı́as propias de
Java, las cuales se pueden descargar directamente de la página web de sun.
En nuestro caso se ha trabajado con la última versión actual JDK 1.4.1 que
se ha podido descargar de http://java.sun.com/j2se/1.4.1/download.html.
Una vez descargado se procede a la instalación, la cual es muy sencilla.
Con esta descarga se consigue el archivo j2re-1 4 0 03-windows-i586-i.exe
el cual con sólo ejecutarlo nos instala la colección de librerı́as de Java JDK
1.4.1 las cuales están listas para ser usadas.
En nuestro proyecto de JBuilder bastará realizar un import del paquete
o clase querida para poder trabajar con sus clases o métodos, como ya se
entiende que se sabe.
Para poder trabajar con JDK es muy importante poder continuamente
ver el conjunto de paquetes y de clases (API )para poder buscar y encontrar lo necesitado en cada momento. Esto se ha conseguido con tener
constantemente contacto con la página web de sun que muestra esta API.
La figura 6.14 muestra la organización de esta API de Java:
132
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
6.3. USO DE LIBRERÍAS JDK 1.4.1
Figura 6.14: API de JDK 1.4.1.
También debido a la gran amplitud de paquetes, clases y métodos es
muy importante contar con la posibilidad de un grupo de noticias en el
cual poder mostrar nuestras dudas, sugerencias, ver preguntas frecuentes
e intentar consultar nuestros problemas. Se ha contado con el grupo
news.upm.es para dichas consultas.
Esta API es altamente extensa por lo que para usar lo que uno necesita
el mayor problema es encontrarlo, por lo que, como hemos dicho es muy
importante tener un buen servicio de consulta.
6.3.2.
Estructura de JDK 1.4.1.
Los paquetes usados de esta API para nuestra aplicación son unos pocos,
por lo que nos vamos a centrar en comentar someramente sólo éstos debido
a lo expuesto anteriormente referente a la amplitud. Se señalan también
clases e interfaces importantes de cada paquete:
r
GVA-ELAI-UPMPFC0074-03
133
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
java.awt
Contiene todas las clases para la creación de interfaces de usuario y para
la representación gráfica de imágenes. Hay objetos de interfaz de usuario
como un botón o un scrollbar, en la terminologı́a awt, un componente.
La clase Component es la raı́z de todos los componentes awt. Ver la clase
Component para una descripción detallada de las propiedades las que todos
los componentes awt comparten.
Algunos componentes lanzan eventos cuando un usuario interactúa
sobre los componentes. La clase AWTEvent y sus subclases se usan para
representar los acontecimientos los que awt componentes pueden lanzar.
Ver AWTEvent para una descripción del modelo de eventos de awt.
Un container es un componente que puede contener componentes y otros
contenedores. Una container también puede tener a un gerente de disposición que controla la colocación visual de componentes en el contenedor.
El paquete de programas de awt contiene a varios gerentes de disposición
clases y un interfaz para construir su propio gerente de disposición. Ver las
clases Container y LayoutManager para más información.
Clases importantes:
AWTEvent: La clase de eventos raı́z para todos los eventos AWT.
BorderLayout: Un BorderLayout pone de un contenedor, arreglando y
redimensionando su componente para tener cinco regiones: norte, sur,
este, oeste, y centro.
Component: Un componente es un objeto que tiene una representación
gráfica que puede ser mostrada sobre la pantalla y que puede interactuar con el usuario.
Container : Un Abstract Window Toolkit(AWT) el objeto de contenedor es un componente que puede contener otros componentes AWT.
Graphics: La clase Graphics es la clase abstracta base para todos los
contextos de gráficos que permiten a una aplicación dibujar sobre los
componentes que están comprendidos sobre varios dispositivos, ası́ como sobre imágenes fuera de pantalla.
GridBagLayout:La clase GridBagLayout es un gerente de disposición
flexible que alinea componentes verticalmente y horizontalmente, sin
requerir que que los componentes fueran del mismo tamaño.
134
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
6.3. USO DE LIBRERÍAS JDK 1.4.1
Image: La clase abstracta la Imagen es la superclase de todas las clases
que representan imágenes gráficas.
MediaTracker : La clase MediaTracker es una clase de utilidad para
rastrear el estado de un número de objetos media.
...
java.awt.event
Proporciona interfaces y clases para ocuparse de los diferentes tipos de
eventos lanzados por los componentes awt. Ver la clase java.awt.event para
más detalles sobre el modelo de acontecimiento awt. Los acontecimientos
se lanzan por fuentes de eventos. Un oyente de eventos (event listener)
se registra con una fuente de evento para recibir notificaciones sobre los
eventos de un tipo particular. Este paquete de programas define eventos
y oyentes de eventos, ası́ como adaptadores de oyente de acontecimiento,
que son clases que convienen para hacer más fácil el proceso de escribir a
oyentes de acontecimiento.
ActionEvent: Un evento que indica que ocurrió una acción definida de
un componente.
ComponentAdapter : Una clase de adaptador abstracta para recibir
eventos de componentes.
ComponentEvent: Un acontecimiento de bajo nivel que indica que un
componente se ha movido, el tamaño cambiado o la visibilidad cambiada (también es la clase de raı́z para otros acontecimientos de nivel
componente).
MouseEvent: Un evento que indica que una acción de ratón ocurrió en un componente. Ver también MouseMotionAdapter y MouseWheelEvent.
Interfaz ActionListener : El interfaz de oyente (listener interface) para
recibir eventos de acción.
...
java.awt.image
Proporciona clases para la creación y la modificación de imágenes. Las
imágenes son procesadas usando un marco que corre que implica a una
image producer, filtros de imagen opcionales y una image consumer. Este
marco hace posible para progresivamente dar una imagen mientras este se
r
GVA-ELAI-UPMPFC0074-03
135
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
trae y se genera. Además, el marco permite un uso desechar el almacenaje
usado por una imagen y regenerarlo en cualquier momento. Este paquete
proporciona a un número de image producers, consumers, y filtros que se
pueden configurar para nuestras necesidades de procesamiento de imágenes.
Clases importantes de este paquete son:
BufferedImage: La subclase BufferedImage describe una Imagen con
un bufer accesible de datos de imagen.
ColorModel : La clase abstracta de ColorModel encapsula los métodos
para traducir un valor de pixel a un componente de color (por ejemplo,
rojo, verde, y azul) y un componente alfa.
PixelGrabber : La clase PixelGrabber implementa un ImageConsumer
que puede ser atado a una Imagen o a un objeto ImageProducer para
coger los datos de los pı́xeles de esa imagen.
...
java.io
Proporciona la entrada y salida del sistema a través de corrientes de
datos, serialización y el archivo de sistema. Si se pasa un argumento nulo
a un constructor o a algún método de cualquier clase o interfaz en este
paquete hará que un NullPointerException se lance.
Clases importantes:
BufferedInputStream: Un BufferedInputStream agrega la funcionalidad a otra entrada corriente conocida, la capacidad de bufer la entrada
y apoyar la señal y poner resetear métodos.
BufferedOutputStream: La clase implementa un bufferedOutputStream.
FileInputStream: coge bytes de entrada desde un archivo y lo pasa a
un archivo de sistema.
FileOutputStream: es una corriente de salida para la escritura de datos
a un File o a un FileDescriptor.
...
136
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
6.3. USO DE LIBRERÍAS JDK 1.4.1
java.lang.Object
Proporciona las clases que son fundamentales para el diseño del lenguaje
de programación Java. Las clases más importantes son el Object, que es la
raı́z de la jerarquı́a de clase, y la Class.
Con frecuencia es necesario representar un valor de tipo primitivo como
si esto fuera un objeto. Las clases Boolean, Character, Integer, Long, Float,
y Double sirven para este objetivo. Un objeto tipo Doble, por ejemplo,
contiene un campo cuyo tipo es doble, representando aquel valor de tal
modo que una referencia a ello puede ser almacenada en una variable de
tipo de referencia. Estas clases también proporcionan unos métodos para la
conversión entre valores primitivos, ası́ como métodos tan estándar como
equals y hashCode. La clase Void es una clase no instanciable que sostiene
una referencia a un objeto Clase que representa el tipo primitivo void.
La clase Math proporciona comúnmente funciones matemáticas como
el seno, el coseno, y la raı́z cuadrada. Las clases String y StringBuffer
proporcionan de modo similar operaciones comúnmente usadas sobre
cadenas de caracteres.
Las clases ClassLoader, Process, Runtime, SecurityManager, y System
provorcionan .operaciones de sistema”que manejan la carga dinámica de
clases, crean procesos externos, reciben preguntas como la hora del dı́a, y
la ejecutan una polı́tica de seguridad.
La clase Throwable abarca los objetos que pueden ser lanzados por la
declaración de lanzamiento. Las subclases de Throwable representan errores
y excepciones.
Clases importantes: Boolean, Byte, Character, Class, Integer, Long, Math,
Double, Float, Process, Runtime, String ...
javax.swing
Proporciona un juego fácil de usar de componentes (para GUIs) que, al
máximo grado posible, trabajan sobre todo tipo de plataformas.
Clases importantes: JButton, JComboBox, JFileChooser, JFrame, JLabel,
JPanel, JScrollPane, ...
r
GVA-ELAI-UPMPFC0074-03
137
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
6.3.3.
Configuración de JDK en JBuilder.
Por defecto al estar en un proyecto de JBuilder se usa (en esta versión
7) la API 1.3 de JDK. En el caso de que queramos usar otra versión por la
causa que sea (en nuestro caso queremos cambiar a JDK 1.4.1 para poder
usar unas determinadas funciones)se debe proceder de la siguiente manera:
1. Herramientas
2. Configurar JDK...
Figura 6.15: Configurar JDK.
3. En la pantalla siguiente se debe mostrar el camino de la nueva API
mediante el botón Cambiar.
138
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
6.4. INSTALACIÓN DE JDT EN JBUILDER.
Figura 6.16: Nuevo camino de JDK.
De esta forma cambiarı́amos la API para poder trabajar con las nuevas
actualizaciones de ésta. De todas formas a nuestro nivel es casi inútil
trabajar con la versión última y nos podrı́amos conformar con versiones
anteriores sin mermar nuestras posibilidades.
6.4.
Instalación de JDT en JBuilder.
Debido a que se necesita trabajar con estas librerı́as de DICOM, es
necesario indicarle al programa cómo usarlas, es decir, instalarlas.
Este proceso, que serı́a equivalente para cualquier tipo de librerı́as, consta
de las siguientes partes:
1. En la barra de herramientas seleccionar Proyecto.
2. Propiedades de proyecto.
r
GVA-ELAI-UPMPFC0074-03
139
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
Figura 6.17: Propiedades de proyecto.
3. En la pantalla siguiente en la pestaña Vias de acceso y dentro de ésta
en la pestaña Bibliotecas necesarias y pulsando el botón Añadir y
en Nuevo y mediante el asistente de bibliotecas se añade las nuevas
bibliotecas:
140
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
6.4. INSTALACIÓN DE JDT EN JBUILDER.
Figura 6.18: Propiedades de proyecto.
Añadir.
Seleccionar camino: en nuestro caso D:/classpath/jdt.jar y
D:/classpath/jdt.key como podemos ver en la figura.
r
GVA-ELAI-UPMPFC0074-03
141
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
Figura 6.19: Propiedades de proyecto.
4. Hecho ésto en nuestro código podremos ya incluir nuestros nuevos
paquetes como por ejemplo:
import com.archimed.dicom.*;
y una vez hecho ésto podremos definir nuevos objectos de estas nuevas
clases de DICOM como por ejemplo:
private SOPClass sopClass = new SOPClass();
Por lo que ya tenemos instaladas nuestras librerı́as JDT y podemos
empezar a trabajar con ellas.
6.5.
Implementación de nuestra aplicación.
6.5.1.
Introducción.
Una vez instalados y comprendidos todos nuestros recursos para desarrollar la aplicación DICOM, se comienza a implementarla.
142
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia6.5. IMPLEMENTACIÓN DE NUESTRA APLICACIÓN.
6.5.2.
Estructura de la GUI.
Lo primero, y a través de los componentes de javax.swing es construir un
marco que concuerde con las expectativas. En nuestro caso se ha dispuesto
varias pestañas que albergan paneles mediante las clases JTabbedPane y
JPanel para que quede una estructura de interfaz como la representada en
la figura 6.20.
Figura 6.20: Estructura básica de la aplicación.
Y de esta forma poder poner en cada panel lo deseado. En nuestro caso se
ha dispuesto de los paneles que aparecen en la figura: panelProcesamiento,
panelVisorDicom, panelCrearDicom y panelCliente-Servidor (también se
han incluido dos paneles para posibles funciones posteriores).
Vamos a ver para que sirven cada uno de estos paneles y una pequeña
muestra de cómo han sido implementados.
r
GVA-ELAI-UPMPFC0074-03
143
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
6.5.3.
Panel VisorDicom.
Este panel sirve para poder visualizar todo tipo de archivos DICOM:
archivos comprimidos, no comprimidos, en color, en escala de grises y de
una o varias imágenes, también es capaz de insertar datos de texto en los
campos ya existentes de un archivo DICOM y también de crear nuevos
campos e insertar datos en ellos.
Se ha conseguido a través de la implementación de una clase llamada
Imagedos en el proyecto de JBuilder, la cual nos va a permitir en última
instancia ser capaces de visualizar la imagen de los archivos DICOM. Se
recomienda ver el código fuente de esta clase.
Figura 6.21: Panel Visor DICOM.
Visualizar datos: texto e imágenes.
Esta clase tiene un constructor de la forma public Imagedos(DicomObject
dcm) al cual vamos a llamar y a pasarle un objeto de la clase DicomObject.
Este parámetro que se pasa es un archivo DICOM sacado de archivos
.dcm (formato DICOM) los cuales se han conseguido de páginas web que
144
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia6.5. IMPLEMENTACIÓN DE NUESTRA APLICACIÓN.
dejan bajar ejemplos de archivos DICOM.
La forma de pasar de un archivo .dcm a una instancia de la clase
DicomImage (subclase de DicomObject, ver API de JDT) se consigue
mediante este código, implementado en nuestra clase principal MarcoCuatro.java en el método open():
.......
if
(JFileChooser.APPROVE OPTION
==
jFileChooser1.showOpenDialog(this))
openFileName = jFileChooser1.getSelectedFile().getAbsolutePath();
f = new File(openFileName);
fin = new FileInputStream(f );
bis = new BufferedInputStream(fin);
dcm.read(bis, true);
.......
en donde con la primera lı́nea de código conseguimos que se abra un
selector de archivos, donde elegimos el archivo DICOM deseado (ver
clase JFileChooser en la API de JAVA). Con la lı́nea openFileName =
jFileChooser1.getSelectedFile().getAbsolutePath(); conseguimos guardar el
camino completo del archivo, el cual necesitamos para crear un objeto de
la clase File, depués uno de la clase FileInputStream y finalmente uno de
la clase BufferedInputStream para poder usar el método read de la clase
DicomObject, el cual lee desde el BufferedInputStream el archivo DICOM.
De esta forma tenemos en dcm (DicomImage dcm = new DicomImage();)
nuestro archivo DICOM .dcm.
Para sacar los datos de texto de este archivo DICOM usamos:
ReSystemOut systemArea = new ReSystemOut(areaTextoDatosDicom);
dcm.dumpVRs(systemArea,true);
donde la clase ReSystemOut es una implementación realizada para poder
mostrar estos datos en un objeto de la clase JTextArea, que es lo que nos
interesa para poder visualizar estos datos en nuestro GUI (en este caso
en la instancia areaTextoDatosDicom de JTextArea: ver código de la clase
ReSystemOut).
El paso siguiente es coger los datos reunidos en este objecto. Para
r
GVA-ELAI-UPMPFC0074-03
145
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
ello necesitamos la clase Imagedos. Llamamos a su constructor public
Imagedos(DicomObject dcm) con lo que tenemos un objeto de esta clase:
imagedcm = new Imagedos(dcm);
Mediante el método getBufferedImage(int numeroDeImagen) podemos
sacar las imágenes y poderlas visualizar de esta forma:
imagen = imagedcm.getBufferedImage(numeroImagen);
etiquetaMostrarImagen.setIcon(new ImageIcon(imagen));
donde etiquetaMostrarImagen es un objeto de la clase JLabel la cual
mediante el método setIcon(ImageIcon a) puede mostrar nuestras imágenes.
La instancia de la clase ImageIcon se crea como se ve arriba mediante su
constructor (ver clase en API).
Hacer zoom in o zoom out.
Una vez visualizada la imagen, se ha dotado de la posibilidad de hacer
zoom de dos formas diferentes:
1. Botones Zoom In y Zoom Out:
Figura 6.22: Zoom mediante botones Zoom In y Zoom Out.
La implementación básica es (para el caso de Zoom In):
int altura = zoomImagen.getHeight(null);
int anchura = zoomImagen.getWidth(null);
zoomImagen = imagen.getScaledInstance(anchura*2,altura*2,imagen.SCALE DEFAULT);
etiquetaMostrarImagen.setIcon(new ImageIcon(zoomImagen));
donde con getHeight y getWidth (métodos de la clase Image) sacamos
la altura y anchura de la imagen zoomImagen. Y mediante el método
146
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia6.5. IMPLEMENTACIÓN DE NUESTRA APLICACIÓN.
getScaledInstance hacemos una imagen a escala de la anterior, para lo
que necesitamos nuevos datos de alto/ancho, que después con el método
antes visto setIcon podemos visualizamos en el mismo objeto JLabel,
etiquetaMostrarImagen.
2. Mediante eventos de ratón:
Figura 6.23: Zoom mediante cliqueos de ratón.
En este caso se ha conseguido que mediante dos cliqueos con el ratón
sobre la imagen se haga zoom IN de la zona selecionada. Se hace, creando
para la JLabel deseada (etiquetaMostrarImagen), un código que sea capaz
de recoger un evento, en este caso el chasquido del ratón. La implementación
es:
etiquetaMostrarImagen.addMouseListener(new MouseAdapter()
r
GVA-ELAI-UPMPFC0074-03
147
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
{
public void mousePressed(MouseEvent e)
{
try
if(x1==-1&y1==-1)
{
x1 = e.getX();
y1 = e.getY();
}
else if(x2==-1&y2==-1)
{
x2 = e.getX();
int ancho = Math.abs(x2) - Math.abs(x1);
int alto = y2 - y1;
ancho = Math.abs(ancho);
alto = Math.abs(alto);
zoomBufferedImagen
=
ImageToBufferedImage.toBufferedImage(zoomImagen);
if((x1>x2)&(y1>y2))
{
zonaBImagen= zoomBufferedImagen.getSubimage(x2,y2,ancho,alto);
}
if((x1<x2)&(y1>y2))
{
zonaBImagen= zoomBufferedImagen.getSubimage(x1,y2,ancho,alto);
}
if((x1<x2)&(y1>y2))
{
zonaBImagen= zoomBufferedImagen.getSubimage(x1,y1,ancho,alto);
}
if((x1>x2)&(y1<y2))
{
zonaBImagen= zoomBufferedImagen.getSubimage(x2,y1,ancho,alto);
}
Image
zonaZoomImage
=
zonaBImagen.getScaledInstance(4*ancho,4*alto,Image.SCALE DEFAULT);
Marco PantallaCompleta
marcoZonaZoom
=
new
Marco PantallaCompleta(zonaZoomImage);
Dimension dlgSize = marcoZonaZoom.getPreferredSize();
Dimension frmSize = getSize();
Point loc = getLocation();
marcoZonaZoom.setLocation((frmSize.width - dlgSize.width) / 2 +
148
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia6.5. IMPLEMENTACIÓN DE NUESTRA APLICACIÓN.
loc.x, (frmSize.height - dlgSize.height) / 2 + loc.y);
marcoZonaZoom.setModal(true);
marcoZonaZoom.pack();
}
}
});
donde se crea un listener de evento MouseEvent el cual nos permite
saber la posición del ratón en el momento que éste es pulsado, por lo que
podemos sacar la zona de interés (mediante los métodos getX() y getY()
) y donde Marco PantallaCompleta es una clase que permite visualizar
imágenes en un panel aparte. Se sugiere ver código de esta última clase.
También, si se quisiese detectar, por ejemplo el movimiento del ratón sobre
un componente o el rotar de la rueda central del ratón se pueden usar clases
del mismo paquete MouseAdapter, MouseEvent, MouseMotionAdapter o/y
MouseWheelEvent para tener efectos homólogos a lo anteriormente visto.
Visualizar todas las imágenes.
Ya se ha comentado la forma de conseguir visualizar los datos de la
imagen de los archivos DICOM, pero también sabemos que un archivo
DICOM puede contener más de una imagen, por lo que debemos ser capaces
de visualizarlas todas y cada una de ellas.
Al abrir un archivo DICOM se muestra en pantalla (en una instancia
de la clase JLabel) la primera imagen y en el caso de que haya más de
una imagen en dicho archivo, los botones Siguiente, Anterior y Seguidas
realizarán las funciones siguientes.
1.- Botones Siguiente y Anterior :
Figura 6.24: Botones Anterior y Siguiente
r
GVA-ELAI-UPMPFC0074-03
149
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
Estos dos botones permiten ver, si existe, la imagen siguiente o la anterior
como indica su nombre. La implementación es muy sencilla. Primero, se ve
si hay más de una imagen mediante la captura del dato del objeto DICOM
dcm.getI(DDict.dNumberOfFrames) (ver página 66) y si existe, se muestra
en pantalla.
La parte importante de esta implementación es:
void botonImagenSiguiente actionPerformed(ActionEvent e)
{
.....
.....
numeroImagen++;
imagen=imagedcm.getBufferedImage(numeroImagen);
etiquetaMostrarImagen.setIcon(new ImageIcon(imagen));
.....
.....
}
Donde imagedcm es un objeto de la clase Imagedos que puede coger
la imagen de número seleccionada mediante el int numeroImagen (Ver
implementación de Imagedos.java). Se visualiza como antes.
2.- Botón Seguidas:
Figura 6.25: Botón Seguidas
Se basa en lo anterior, pero se consigue que las imágenes pasen una detrás
de otra (formando una especie de pelı́cula por supuesto en el caso de que
haya más de una). La pelı́cula se para si se pulsa con el ratón sobre el panel
donde aparece esta secuencia.
Se va a ver una parte importante de la implementación:
150
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia6.5. IMPLEMENTACIÓN DE NUESTRA APLICACIÓN.
void botonImagenesSeguidas actionPerformed(ActionEvent e)
{
.....
.....
Image [] secuencia = new Image[dcm.getI(DDict.dNumberOfFrames)];
for(int n=0;n¡dcm.getI(DDict.dNumberOfFrames);n++)
{);
secuencia[n]=imagedcm.getBufferedImage(n);
System.out.println(n);
}
cargado = true;
ImageSequenceTimer controller = new ImageSequenceTimer();
controller.secuencia(secuencia,dcm.getI(DDict.dNumberOfFrames));
.....
.....
}
donde, como se puede ver, se cargan todas las imágenes en un array de
Images y más tarde se crea una instancia de la clase ImageSequenceTimer
con la cual se crea el panel donde se va a visualizar la secuencia. Ver
implementación de la clase ImageSequenceTimer.
Guardar imágenes como JPEG.
Figura 6.26: Botón Guardar JPEG
Se puede guardar la imagen visualizada en formato JPG mediante las
posibilidades de JDK 1.4.1. Esta función sólo se encuentra en esta versión de la API JAVA, por lo que aquı́ vemos el porqué del uso de esta versión.
Para implementar esto necesitamos importar el paquete:
r
GVA-ELAI-UPMPFC0074-03
151
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
import javax.imageio.*;
debido a que en éste se encuentra lo buscado, que es el método de la clase
javax.imageio.ImageIO que nos permite guardar los datos de una instancia
de la clase Image en un archivo de formato JPEG. La implementación
esencial es:
void botonGuardarIamgenComoJpg actionPerformed(ActionEvent e)
{
.....
.....
if
(JFileChooser.APPROVE OPTION
==
jFileChooser1.showSaveDialog(this))
{
String salvarJPG = jFileChooser1.getSelectedFile().getAbsolutePath();
FileOutputStream salvar = new FileOutputStream(salvarJPG);
File save = new File(salvarJPG);
BufferedOutputStream salida = new BufferedOutputStream(salvar);
javax.imageio.ImageIO.write(imagen,”JPEG”,save);
}
.....
.....
}
donde la lı́nea importante es javax.imageio.ImageIO.write(imagen,”JPEG”,save);
que realiza la función deseada.
Meter y modificar datos de texto en el archivo DICOM.
En un archivo DICOM, como sabemos tenemos datos de imagen y
también de texto, es decir el nombre del paciente, que aparato ha realizado
la captura de la imagen ... La función, que se ha hecho para esta GUI y
para este panel, es la capacidad de poder añadir datos de texto al archivo
visualizado.
Esto se puede hacer de dos formas diferentes. Se puede insertar datos
en campos ya existentes, como el nombre del paciente, o se puede crear
nuestro propio campo como por ejemplo número de moléculas infectadas.
Del primer tipo se han dispuesto una serie de campos, los cuales pueden
152
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia6.5. IMPLEMENTACIÓN DE NUESTRA APLICACIÓN.
ser válidos o no. En este aspecto deben ser los profesionales de la medicina
los que deben suministar información para saber los datos que quieren
insertar para poder adaptarnos a ellos.
Ya se vió de que manera se puede visualizar todos los datos del archivo
DICOM (ver páginas 71 y 145 en seciones 4.2.2 y 6.5.3 respectivamente);
aquı́ vamos a cambiar o entrar nuevos datos en determinados campos y
podremos visualizar si estas modificaciones se llegan a producir.
Para ésto se han dispuesto dos instancias de la clases JComboBox, dos
botones de la clase JButton para insertar y para ver lo insertado y de dos
objetos JTextArea siendo éstas las zonas de visualización. Todo esto se
puede ver en la figura 6.27
Figura 6.27: Zona de insertar datos.
La forma de implementar esto es creando dos instancias de la clase
JComboBox con los campos que tengan que aparecer según lo comentado
más arriba:
private JComboBox jComboBox1
= new JComboBox(opcionesCombobox);
siendo en este caso opcionesCombobox :
String[] opcionesCombobox = {”dAdditionalPatientHistory”
,”dBeamName”,”dBitsAllocated”,”dBodyPartExamined”,”dContrastAllergies”
,”dHistogramData”,”dImageComments”,”dInterventionDrugName”,”dModality”
,”dPatientName”,”dPixelData”,”dROIArea”,”dSeriesNumber”,”dSmokingStatus”
,”dNumberOfFrames”};
r
GVA-ELAI-UPMPFC0074-03
153
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
por lo que al pinchar sobre la flecha del combobox, aparecen todos estos
campos. Ahora hay que interconectarlos para que al seleccionar uno y
escribir sobre las JTextArea se inserte y visualicen los datos.
Esto se consigue, a grandes rasgos, mediante esta codificación:
Para insertar:
void botonInsertarDato actionPerformed(ActionEvent e)
{
try
{
String opcion = (String)jComboBox1.getSelectedItem();
String dato = areaTextoInsertarDato.getText();
if(opcion==”dPatientName”)
dcm.set(DDict.dPatientName, new Person(dato));
.....
donde new Person(dato) es el dato del nombre del paciente que se inserta
en el campo del archivo DICOM DDict.dPatientName.
Hecho esto, el dato estarı́a en el objeto DicomImage pero no todavı́a en
el archivo .dcm, para lo que se implementa estas otras lı́neas de código:
FileOutputStream save = new FileOutputStream(openFileName);
dcm.write(save,true);
siendo write un método de la clase DicomObject que lo que hace es
escribir a través de un FileOutputStream todos los datos de la instancia
DicomImage en un archivo .dcm que, si no existe, crea uno.
Para ver lo insertado:
void botonVerDato actionPerformed(ActionEvent e)
{
String opcion2 = (String)jComboBox2.getSelectedItem();
if(opcion2==”dPatientName”)
{
String cadena = dcm.getS(DDict.dPatientName);
areaTextoVerDato.setText(dcm.getS(DDict.dPatientName));
.....
Para ver que el funcionamiento de lo anterior es correcto se puede volver
154
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia6.5. IMPLEMENTACIÓN DE NUESTRA APLICACIÓN.
a abrir el archivo DICOM y se podrá observar que el nombre del paciente
ha cambiado o aparece cosa que antes no harı́a. La figura siguiente pretende
servir de ejemplo de lo descrito.
Figura 6.28: Ver funcionamiento.
Cómo añadir campos nuevos al archivo DICOM
La otra posibilidad, como se ha comentado, es la de insertar nuestros
propios campos.
Se ha visto cómo insertar datos en los campos del archivo DICOM
existentes ya, como el sexo del paciente, nombre del fabricante, ID del
paciente, etc, pero es muy importante ser capaces de crear nuestros propios
campos, como por ejemplo el número de virus, diagnóstico del médico, y en
definitiva, los que se crean convenientes.
Para ello se han dispuesto en la GUI ciertos botones (figura 6.29) que son
capaces hacer este servicio.
r
GVA-ELAI-UPMPFC0074-03
155
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
Se tiene la posibilidad de crear campos donde se albergan datos de tipo
Integer o datos de tipo String, es decir, campos para datos numéricos y
campos para datos de texto.
Figura 6.29: Botones para campos nuevos.
El código básicamente es:
void jButton6 actionPerformed(ActionEvent e)
{
.......
DDictEntry
entrarDDict1
=
new
DDictEntry(new
Integer(campoGrupoNumero.getText()) .intValue(), new Integer (campoElementoNumero.getText()).intValue(), DDict.tUS,campoNuevoNumero.getText(),
”1”);
diccionario.addEntry(entrarDDict1);
dcm.set ge(new
Integer(campoGrupoNumero.getText()).intValue(),
new
Integer(campoElementoNumero.getText()).intValue(),new
Integer(numero.getText()));
.......
}
Como se ve es la implementación que se ejecuta en el momento en que el
156
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia6.5. IMPLEMENTACIÓN DE NUESTRA APLICACIÓN.
botón en cuestión es pulsado.
Lo primero que se hace es crear una instancia de la clase DDictEntry.
Al pasar los parámetros vistos fijamos el número de grupo, el número de
elemento, la descripción del campo y el tipo de dato DICOM que se puede
meter en éste campo. Ver clases DDictEntry y DDict en la API de JDT la
clase DDictEntry para más detalles.
Una vez hecho esto, creamos un objeto de la clase DDict, en la cual vamos
a insertar nuestro nuevo campo por medio del método addEntry(DDictEntry
a).
En este momento tenemos la posibilidad de poder meter en el objeto de la clase DicomObject (dcm) el nuevo dato mediante el método
set ge(grupo,elemento,dato), que en este caso debe ser un Integer ya que el
tipo US DICOM es tipo Integer en Java (ver conversiones DICOM/JAVA,
JAVA/DICOM tablas en páginas 67 y 68).
Se puede comprobar que el nuevo campo se inserta bien:
Figura 6.30: Comprobar inserción de nuevo campo.
r
GVA-ELAI-UPMPFC0074-03
157
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
Para el caso de insertar un campo que alberge un dato de tipo String se
ha procedido de la misma forma:
void jButton5 actionPerformed(ActionEvent e)
{
.......
DDictEntry
entrarDDict2
=
new
DDictEntry(new
Integer(campoGrupoTexto.getText()) .intValue(), new Integer (campoElementoTexto.getText()).intValue(), DDict.tST,campoNuevoTexto.getText(),
”1”);
diccionario.addEntry(entrarDDict2);
dcm.set ge(new
Integer(campoGrupoTexto.getText()).intValue(),
new
Integer(campoElementoTexto.getText()).intValue(),new
Integer(numero.getText()));
.......
}
donde lo único que cambia es el tipo de dato que vamos a insertar, por lo
que el tercer parámetro que se pasa al constructor de la clase DDictEntry
es DDict.tST, que es lo que indica esto.
6.5.4.
Panel Crear DICOM.
La función de este panel es la de poder crear un archivo DICOM a partir
de imágenes de formato jpeg y por supuesto datos de texto.
Los datos de texto como el nombre del paciente, el aparato que hace la imagen, la parte del cuerpo examinada, etc, se insertan de la misma forma que
la vista en la sección 6.5.3 y (página 154). Consultar también la sección 4.2.2.
La parte nueva con respecto al panel de visualización de archivos DICOM
(páginas 144 hasta 155) es la zona de meter los datos de imágenes nuestras
en formato jpeg dentro del nuevo archivo DICOM.
Los campos de texto a añadir en el archivo DICOM a crear pueden ser
cambiados, como ya se ha visto.
Estructura del panel Crear DICOM.
Esta estructura la podemos ver en la figura siguiente:
158
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia6.5. IMPLEMENTACIÓN DE NUESTRA APLICACIÓN.
Figura 6.31: Panel Crear archivo DICOM.
Este panel consta de varias partes:
1. Zona de visualización de imágenes a insertar (figura 6.32).
r
GVA-ELAI-UPMPFC0074-03
159
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
Figura 6.32: Imagen a insertar.
2. Zona de inserción de datos de texto (figura 6.33).
160
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia6.5. IMPLEMENTACIÓN DE NUESTRA APLICACIÓN.
Figura 6.33: Datos de texto a insertar.
Inserción de una sóla imagen.
En esta parte vamos a ver la forma de cómo insertar los datos de una
sóla imagen.
Lo primero que se hace es visualizar la imagen a insertar en el área
destinada mediante el botón Abrir imagen y después mediante los botones
Monochrome y RGB metemos la imagen según sea en escala de grises o en
color respectivamente.
Al abrir la imagen se graba la imagen en una instancia de la clase Image
r
GVA-ELAI-UPMPFC0074-03
161
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
(Image imagenJPG;) con la que se trabaja de esta manera:
1. Botón Monochrome:
La implementación de la función de este botón es de la forma:
void botonCrearDicomGris actionPerformed(ActionEvent e)
{
.......
String
rutaArchivoDicomGuardar
=
jFileChooser1.getSelectedFile().getAbsolutePath();
int[] pix = image2IntArray(imagenJPG);
dcmNueva.set(DDict.dSOPClassUID,”1.2.840.10008.5.1.4.1.1.7”);
dcmNueva.set(DDict.dSOPInstanceUID,”1.2.840.10008.5.1.4.1.1.7”);
dcmNueva.imagePixelData(imagenJPG.getHeight(null),imagenJPG.getWidth(null),
8,8,7,pix);
dcmNueva.write(salvar,true);
.......
}
donde image2IntArray es un método que mediante la clase PixelGrabber (ver API JDK) es capaz de coger los datos de la imagen pixel a pixel,
por lo que el resultado es un array de int donde se encuentran estos datos.
Las dos lı́neas siguientes se colocan debido a que son datos que se deben
encontrar obligatoriamente en un archivo DICOM, ya que sin ellos no es
posible crear el archivo.
Más tarde, en nuestra instancia de la clase DicomImage (DicomImage
dcmNueva = new DicomImage();) se insertan estos datos de imagen
mediante el método de esta clase imagePixelData(int filas, int columnas, int
planarConf, int[] pixelData) (ver API JDT). También se han probado los
métodos vistos en la sección 4.2.4 donde, por lo comprobado, sólo funcionan
los métodos de DicomObject y DicomImage y no ası́ los métodos mediante
ImageProducer.
Una vez hecho ésto se puede comprobar que los resultados son satisfactorios al ir al panel VisorDicom y tratar de abrir el archivo creado, donde
podemos ver los resultados siguientes:
162
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia6.5. IMPLEMENTACIÓN DE NUESTRA APLICACIÓN.
Figura 6.34: Comprobar la creación del archivo DICOM en escala de grises.
Vemos que la imagen se ha grabado junto con los datos metidos, en
este caso el nombre del paciente, los datos de la imagen y los datos SOP
(”Service Object Pair”).
1. Botón RGB :
Para el caso de la imagen en color se realiza de la misma forma; la diferencia es que se usa otra implemtentación del método imagePixelData ya
que es un método sobrecargado y se utiliza debido al cambio de parámetros
que se pasan a éste:
imagePixelData(int rows, int cols, int planarConf, int[] pixelData);
por lo que queda de la siguiente manera:
dcmNueva.imagePixelData(imagenJPG.getHeight(null),imagenJPG.getWidth(null),
0,pix);
Los resultados se pueden comprobar igualmente visualizando el archivo
r
GVA-ELAI-UPMPFC0074-03
163
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
creado:
Figura 6.35: Comprobar la creación del archivo DICOM en color.
Compresión de archivos DICOM (Monochrome).
Se ha visto cómo crear un archivo DICOM de escala de grises, pero al
hacer ésto se tiene un problema: el tamaño de los archivos es muy grande
debido a que no se ha realizado ningún tipo de compresión a los datos de
los pı́xeles, por lo que el espacio que ocupan es bastante grande.
Para ello se ha recurrido a la clase de la API de JDT llamada Compression, la cual proporcina métodos para realizar compresiones de estos datos.
Para realizar la compresión, como vimos en la sección 4.2.4, página 78, se
actúa de la siguiente forma:
void botonComprir actionPerformed(ActionEvent e)
164
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia6.5. IMPLEMENTACIÓN DE NUESTRA APLICACIÓN.
{
.......
Compression c = new Compression(dcmNueva);
c.compress(TransferSyntax.JPEGLossless);
.......
}
se crea una instancia de la clase Compression (c) que después usa su
método compress, el cual necesita saber el tipo de compresión a usar. En
este momento se tiene que decir que el único tipo de compresión que realiza
este servicio es el señalado arriba, TransferSyntax.JPEGLossless, mientras
que con los otros tipos no consiguen lo buscado con la limitación de que
funciona sólo con imágenes monochrome.
La diferencia de tamaño de un archivo comprimido a uno sin comprimir
es:
No comprimido: tamaño = X
Comprimido: tamaño = X / 2
Tamaño archivo sin comprimir x 2 = Tamaño archivo comprimido
(aproximadamente.)
Inserción de varias imágenes.
Para este caso se ha introducido en un array de Image todas las imágenes
que se quieren insertar en el archivo DICOM.
Una vez insertadas, se procede a sacar los datos de pı́xeles de estas
instancias Image. En este caso se van a guardar estos datos en una matriz
de bytes en vez de array de int.
Teniendo la matriz de bytes (byte[][]), se continúa uniendo todos estos
bytes en un sólo array de bytes (byte[]) donde van uno detrás de otro.
Una vez hecho ésto se procederá a insertar estos datos en el archivo
DICOM a crear.
Para todo esto se usan diferentes botones que realizan las diferentes
funciones vistas antes:
1. Botón No de imágenes: donde se señala el número de imágenes que
vamos a insertar. En el código se da valor a una variable que es
r
GVA-ELAI-UPMPFC0074-03
165
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
utilizada para saber el número de instancias Image que se deben
guardar en el array Image[].
La implementación es:
void iniciarArrayImages actionPerformed(ActionEvent e)
{
imagenSecuencia
=
new
Image
[new
ger(datoPantalla.getText()).intValue()];
}
Inte-
2. Botón Abrir imágenes a insertar : mediante este botón se van almacenando el array las imágenes, hasta que se almacena la última, y es
en este momento cuando aparece un nuevo cuadro que te pregunta
por el lugar y el nombre en donde insertar este arhivo DICOM. La
implementación básica es:
void botonAbrirImagen actionPerformed(ActionEvent e)
{
........
imagenSecuencia[numeroDeImagen] = imagenJPG;
numeroDeImagen++;
int imagenesTotales = new Integer(datoPantalla.getText()).intValue();
if(numeroDeImagen == imagenesTotales)
{
byte[][] secuenciaBytes = new byte[imagenesTotales][];
int n,nBytes=0;
for(n=0;n<imagenesTotales;n++)
{
byte[] ver = image2ByteArray(imagenSecuencia[n]);
secuenciaBytes[n]=image2ByteArray(imagenSecuencia[n]);
}
arrayDeArrayDeBytes=secuenciaBytes;
byte[] todoJunto = unirBytesArray(secuenciaBytes,imagenesTotales);
todosBytesJuntos = todoJunto;
if
(JFileChooser.APPROVE OPTION
==
jFileChooser1.showSaveDialog(this))
{
try
{
String
rutaArchivoDicomGuardar
=
jFileChoos166
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia6.5. IMPLEMENTACIÓN DE NUESTRA APLICACIÓN.
er1.getSelectedFile().getAbsolutePath();
........
dcmNueva.imagePixelData (imagenJPG.getHeight(null),
JPG.getWidth(null), 8,8,7,todosBytesJuntos);
........
dcmNueva.write(salvar,true);
........
}
}
}
imagen-
como se ve en este código, una vez recogidas todas las instancias Image
en el array, se pasa a sacar de cada objeto Image sus datos de pı́xeles
y se reunen en una matriz de bytes llamada arrayDeArrayDeBytes.
Una vez hecho esto, se unen esos array de bytes en uno sólo mediante
el método unirBytesArray(byte[][] secuencia, int numeroDeImagenes),
el cual es el dato a insertar en nuestro archivo DICOM, donde se
recogen todas nuestras imágenes.
Una vez hecho lo anterior, podemos ver los resultados:
Figura 6.36: Resultados de nuestra secuencia.
Comprimir archivo DICOM de varias imágenes monochrome.
Este archivo está sin compresión. Se puede realizar una compresión como
la indicada antes (164) y la reducción de tamaño es de la relación 2 a 1
aproximadamente, es decir el tamaño del archivo comprimido es la segunda
parte del archivo sin comprimir.
r
GVA-ELAI-UPMPFC0074-03
167
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
Igual que lo anteriormente comentado, el único sistema de compresión soportado sigue siendo JPEGLossless de estas librerı́as y más particularmente
de la clase Compression.
6.5.5.
Panel Procesamiento.
Este panel (figura 6.37) sirve para poder procesar una imagen mediante
un algoritmo desarrollado por el GVA. Este panel visualiza la imagen
de origen a procesar y ejecuta el procesamiento y cuando acaba éste se
visualiza en el panel de al lado imagen procesada.
Para realizar este panel se ha contado con la ayuda de los creadores del
algoritmo para poder instalar las librerı́as necesarias. Se a procedido de la
siguiente manera:
Figura 6.37: Panel procesamiento.
Introducción de algoritmo en la aplicación.
Pasos a seguir:
168
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia6.5. IMPLEMENTACIÓN DE NUESTRA APLICACIÓN.
1. Lo primero que se debe hacer es poner en las variables de entorno los
caminos para encontrar las librerı́as necesarias:
D:/jmonrubia/AWouter/bin/win32;
D:/jmonrubia/AWouter;
c:/matlab6p5/bin/win32;
Esto significa que antes se ha debido copiar en estas carpetas los
archivos solicitados.
En la carpeta D:/jmonrubia/AWouter se deben copiar los archivos
applylut.dll y dataread.dll.
2. Después se debe ejecutar el setup mglinstaller.exe que instala las librerı́as necesarias de Matlab.
3. Por supuesto se debe
D:/jmonrubia/AWouter.
copiar
el
ejecutable
en
la
carpeta
4. Después se tiene que crear una carpeta donde se ponen las librerı́as
para sólo este algoritmo:
C:/matlab6p5/toolbox/images/images/private y se incluyen en ésta
bwlabel1.dll y bwlabel2.dll.
Esto es a nivel de sistema. Una vez hecho ésto se debe realizar una
implementación para que este algoritmo se pueda ejecutar desde nuestro
GUI (graphical user interface). Para hacer esto se dan estos pasos:
En el panel de procesamiento se han creado dos JLabel donde poner
las imágenes de origen y la de salida o procesada. Se ha incluido además
una JTextArea para decir el camino y el nombre de la imagen procesada y
dos botones, uno para abrir la imagen a procesar y otro para empezar el
procesamiento. Esto se puede ver en la figura 6.37.
Pasos en JBuider7.0:
1.- Incluir en el proyecto los archivos CntVirRel.exe y files.txt mediante
el botón que se muestra en la figura 6.38:
r
GVA-ELAI-UPMPFC0074-03
169
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
Figura 6.38: Botón para añadir archivos.
2.- Se ha implementado de esta forma.
En el botón Imagen a tratar (figura 6.39):
void botonSeleccionImagen actionPerformed(ActionEvent e)
{
.....
fotoEntradaCamino = jFileChooser1.getSelectedFile().getAbsolutePath();
ImageIcon iconoEntrada = new ImageIcon(fotoEntradaCamino);
imagenEntrada = iconoEntrada.getImage();
etiquetaImagenEntrada.setIcon(iconoEntrada);
String caminoFicheroTxt = ”files.txt”;
File filesTxt= new File(caminoFicheroTxt);
FileOutputStream chorro = new FileOutputStream(filesTxt);
PrintStream escribirEnArchivo = new PrintStream(chorro);
escribirEnArchivo.println(fotoEntradaCamino);
imagenProcesada = textoImagenSalida.getText();
escribirEnArchivo.println(imagenProcesada);
etiquetaSeleccionImagen.setText(fotoEntradaCamino);
......
170
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia6.5. IMPLEMENTACIÓN DE NUESTRA APLICACIÓN.
donde se muestra la imagen de entrada (setIcon) y se escribe el camino
de entrada y de salida en el fichero files.txt de donde después con el botón
que se ve acontinuación se saca esta información.
Figura 6.39: Botón para abrir imagen a procesar.
En el botón Procesar imagen (figura 6.40) básicamente se codifica de la
siguiente manera:
void botonProcesamiento actionPerformed(ActionEvent e)
{
Process p = Runtime.getRuntime().exec(”d:/jmonrubia/AWouter/CntVirRel.exe”);
int valorRetorno = p.waitFor();
ImageIcon iconoSalida = new ImageIcon(textoImagenSalida.getText());
etiquetaImagenSalida.setIcon(iconoSalida);
.....
donde las clases importantes son Process con su método getRuntime().exec() para ejecutar en este caso un .exe y también el método
waitFor() que hace que la ejecución del código se pare hasta que el proceso
p no finaliza. Una vez hecho esto sólo falta mostrar la imagen de salida en
pantalla, cosa que ya se estudió en su debido momento (ver sección 6.5.3 en
página 146).
Figura 6.40: Botón para procesar imagen.
r
GVA-ELAI-UPMPFC0074-03
171
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
6.5.6.
Panel Cliente/Servidor.
Uno de los mayores objetivos de esta aplicación es la posibilidad de
poder mandar y recibir los archivos DICOM a través de la red. Para esta
funcionalidad se ha creado este panel (figura 6.41), el cual permite enviar
un archivo en formato DICOM por la red.
Figura 6.41: Panel Cliente/Servidor.
Para la implementación de este panel se ha insertado en él varias etiquetas y cuatro instancias de la clase JTextArea que se usarán para este servicio.
La implementación consta de básicamente:
void enviar actionPerformed(ActionEvent e)
172
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
6.6. DISTRIBUCIÓN DE LA APLICACIÓN.
{
open();
..........
Storagescu enviar = new Storagescu(servidor,puerto,Tservidor,Tcliente,openFileName);
..........
int ok=enviar.store();
if(ok==enviar.STORE OK)
etiquetaEnvio.setText(”Enviado con éxito”);
else
etiquetaEnvio.setText(”Enviado sin éxito”);
..........
donde los parámetros servidor,puerto,Tservidor,Tcliente,openFileName
corresponden a los datos necesarios para enviar más tarde el archivo
mediante el método store() de la clase Storagescu, que emplazamos a que
sea estudiada.
6.6.
6.6.1.
Distribución de la aplicación.
Generación del archivo ejecutable java.
Una vez hecha esta versión Beta de nuestra aplicación DICOM es
importante poder distribuirla para que sea ejecutada donde sea necesario,
que es uno de los objetivos más importantes.
Contamos con las ventajas de Java, que en este caso concreto es que
independientemente del sistema operativo se puede ejecutar la aplicación.
Para hacer ésto se cuenta con un asistente de JBuilder que se llama asistente Creador de recopilatorios, el cual se puede seleccionar de la forma en
que muestra la figura 6.42:
r
GVA-ELAI-UPMPFC0074-03
173
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
Figura 6.42: Asistente creador de recopilatorios.
Pasos a seguir:
1. Paso 1: seleccionar Aplicación.
2. Paso 2: escribir el nombre del ejecutable java.
Figura 6.43: Asistente creador de recopilatorios. Paso2.
174
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
6.6. DISTRIBUCIÓN DE LA APLICACIÓN.
3. Paso 3: En este paso se selecciona la opción de Incluir siempre todas
las clases y recursos necesarios.
4. Paso 4: Lo mostrado en la figura siguiente son las opciones que se
eligen.
Figura 6.44: Asistente creador de recopilatorios. Paso3.
5. En los pasos 5,6 y 7 se aceptan las opciones por defecto.
Una vez hecho esto se debe compilar el proyecto otra vez, con lo que
conseguimos el archivo recopilado en este caso Cuatro.jar.
6.6.2.
Ejecución del archivo ejecutable java.
Generado este archivo es posible ejecutar esta aplicación con la sóla
teniencia de la herramienta de JDK instalada (en este caso 1.4.1).
La forma de proceder para poder ejecutar este archivo es muy sencilla.
En la lı́nea de comandos donde se encuentre el archivo se debe escribir:
java -jar cuatro.jar
con lo que la aplicación aparece en pantalla.
r
GVA-ELAI-UPMPFC0074-03
175
CAPÍTULO 6. DESARROLLO DE NUESTRA APLICACIÓN
MEDIANTE JDT, JDK 1.4.1 Y JBUILDER7.
José Ma Onrubia
176
r
GVA-ELAI-UPMPFC0074-03
Apéndice A
ESTÁNDAR DICOM
PARTE 1
A.1.
Introducción.
Descripción.
ACR (Colegio Americano de Radiologı́a) y NEMA (la Asociación de
Fabricantes Nacional Eléctrica) formaron un comité conjunto para desarrollar un estándar para la imagen digital y las comunicaciones en medicina.
Este estándar (DICOM) ha sido desarrollado según los procedimientos
NEMA. Ha sido desarrollado conjuntamente con otras organizaciones
de estandarización entre las que se incluyen el centro TC251 en Europa
y el JIRA en Japón, contando también con la supervisión de otras
organizaciones en las que se incluyen IEEE, HL7 Y ANSI en EE.UU.
El estándar DICOM está estructurado como un documento dividido en
varias partes que usan las directrices establecidas en el documento siguiente:
- ISO/IEC Directrices, 1989 Parte 3: Esquema y presentación de Normas
Internacionales.
Este documento es una parte del estándar DICOM, que consiste en las
siguientes partes:
PS 3.1: Introducción y descripción.
PS 3.2: Estatuto de conformidad.
PS 3.3: Definiciones de objeto de información (IOD´s).
PS 3.4: Datos especı́ficos de clase de servicio.
PS 3.5: Estructura de datos y codificación.
177
APÉNDICE A. ESTÁNDAR DICOM PARTE 1
José Ma Onrubia
PS 3.6: Diccionario de datos.
PS 3.7: Intercambio de mensajes.
PS 3.8: Soporte de comunicación en red para el intercambio de mensajes.
PS 3.9: Soporte para la comunicación punto a punto para el intercambio de mensajes.
PS 3.10: Almacenamiento y formato de archivos para el intercambio
de datos.
PS 3.11: Almacenamiento media de perfiles de aplicación.
PS 3.12: Funciones de almacenamiento y formatos media para intercambio de datos.
PS 3.13: Soporte para la impresión en una comunicación punto a punto.
PS 3.14: Función de visualización estándar en escala de grises.
PS 3.15: Perfiles de seguridad.
PS 3.16: Çontent mapping resource”.
Estas partes están relacionadas, pero son documentos independientes. Su
nivel de desarrollo y el su nivel aprobación pueden diferenciarse. Se va a ver
el primer documento.
Historia
Con la introducción de la tomografı́a calculada (CT) seguido por otros
tipos de imágenes digitales para diagnósticos en los años 1970, y el empleo
creciente de ordenadores en aplicaciones clı́nicas, el Colegio Americano
de Radiologı́a (ACR) y la Asociación de Fabricantes Nacional Eléctrica
(NEMA) reconoció la necesidad emergente de un método estándar para la
transferencia de imágenes y la asociación de información entre dispositivos
fabricados por diferentes vendedores. Estos dispositivos producen una variedad de formatos de imagen digitales. El Colegio Americano de Radiologı́a
(ACR) y la Asociación de Fabricantes Nacional Eléctrica (NEMA) formó un
comité conjunto en 1983 para desarrollar un estándar que:
Promueve la comunicación de información de imágenes digitales, independientemente del fabricante del dispositivo de captura.
178
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
A.1. INTRODUCCIÓN.
Facilita el desarrollo y la expansión para archivar las imágenes y para
sistemas de comunicación (PACS) que también puede servir como interfaz con otros sistemas de información de otros hospitales
Permite la creación de las bases de datos de información de diagnósticos que pueden ser solicitados desde una amplia variedad de dispositivos distribuidos geográficamente.
Las normas no 300-1985 de ACR-NEMA publicada en 1985 era la versión
1.0. Al estándar le ha seguido seguido dos revisiones: no 1, octubre de 1986
y no 2, enero de 1988.
Las normas no 300-1988 de ACR-NEMA publicada en 1988 era la versión
2.0. Ésta incluyó la versión 1.0, las revisiones publicadas, y revisiones
adicionales. También proporciona el soporte de comandos para dispositivos
de visualización, presenta un esquema de jerarquı́a nuevo de identificación
de una imagen, y añade datos para incrementar la especificidad a la hora
de describir una imagen.
Estas publicaciones de normas definieron una interfaz de soporte fı́sico,
un juego mı́nimo de instrucciones de software, y un juego constante de
formatos de datos.
El estándar DICOM
El estándar incorpora unas mejoras principales respecto a las versiones
anteriores del estándar:
1. Se aplica a un ambiente de red. Las versiones anteriores eran aplicables
sólo a ambientes de punto a punto; para la operación en un ambiente
de red una unidad de interfaz de Red (NIU) era requerida. La Versión
3.0 de DICOM puede soportar los estándares de comunicación en red
que se usan en industria, como los protocolos OSI Y TCP/IP.
2. Especifica cómo los dispositivos deben cumplir con el estándar para
que los datos y las instrucciones sean intercambiadas. Las versiones
anteriores han sido limitadas a la transferencia de datos, pero la Versión 3.0 DICOM especifica, por el concepto de clases de servicio, la
semántica de órdenes y datos asociados.
3. Especifica los niveles de conformidad. Las versiones anteriores especificaron un nivel mı́nimo de conformidad. DICOM la Versión 3.0, explı́citamente, describe como una implementación debe estructurar una
declaración de conformidad para seleccionar opciones especı́ficas.
r
GVA-ELAI-UPMPFC0074-03
179
APÉNDICE A. ESTÁNDAR DICOM PARTE 1
José Ma Onrubia
4. Está estructurado como un documento dividivo en varias partes. Ésto,
facilita la rápida evolución del estándar simplificando la adición de rasgos nuevos. Las directrices ISO que definen como estructurar documentos de multi-partes han sido seguidas en la construcción del estándar
DICOM.
5. Introduce objetos de información explı́citos no sólo para imágenes y
los gráficos, también para estudios, informes, etc.
6. Especifica una técnica establecida para la identificación única de
cualquier objeto de información lo que facilita las definiciones inequı́vocas de las relaciones entre objetos de información como ellos son interpretados a través de la red.
A.2.
Alcance y campo de aplicación.
El Estándar DICOM facilita la interoperabilidad de un equipo médico
visualizador y creador de imágenes especificando:
un juego de protocolos para que sean cumplidos por los dispositivos.
la sintaxis y la semántica de órdenes y de la información asociada que
puede ser intercambiada usando estos protocolos.
la información que debe ser suministrada para una realización para
cumpla con el estado de conformidad.
El Estándar DICOM no especifica:
los detalles de cualquiera de los rasgos del estándar para que un dispositivo reclamando conformidad para una implementación.
el juego total de rasgos y funciones de un sistema integrado por un
grupo de dispositivos cada uno siguiendo la norma del estándar.
un procedimiento de pruebas y validación para evaluar de que forma
se cumple con el estándar.
El estándar DICOM pertenece al campo de la informática médica. Dentro
de este campo, dirige el intercambio de información digital entre equipos
médicos. Como el equipo médico puede funcionar con otros dispositivos
médicos, el alcance de estas necesidades estándar para trasladar a otras
áreas de informática médica, como mostrado en la figura. Sin embargo, el
estándar DICOM no dirige la anchura de este campo.
180
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
A.3.
A.3. DEFINICIONES.
Definiciones.
Atributo: una caracterı́stica de un objeto de información. Un atributo
tiene un nombre y un valor que es independiente de cualquier esquema de
codificación. Por ejemplo el nombre del paciente.
Comando: un medio genérico de transportar una petición para funcionar
sobre objetos de información a través de una interfaz o una red.
r
GVA-ELAI-UPMPFC0074-03
181
APÉNDICE A. ESTÁNDAR DICOM PARTE 1
José Ma Onrubia
Elemento de comando: una codificación de un parámetro de un comando
que transporta el valor de este parámetro.
Chorro de comandos: el resultado de codificar un conjunto de elementos
de comando DICOM que usan el esquema de codificación DICOM.
Estatuto de conformidad : una declaración formal asociada con una
realización especı́fica del estándar DICOM. Especifica las clases de servicio,
los objetos de información, y los protocolos de comunicación que soportan
por las implementaciones.
Diccionario de datos: un registro de los elementos de datos DICOM que
tienen una etiqueta única, un nombre, un valor, y la semántica de cada
elemento de datos.
Elemento de datos: una unidad de información como definido por una
partida simple en el diccionario de datos.
Conjunto de datos: información intercambiada que consiste en un
conjunto estructurado de valores de atributos directa o indirectamente
relacionados con los objetos de información. El valor de cada atributo en
un conjunto de datos es expresado como un elemento de datos.
Corriente de Datos: el resultado de codificar un conjunto de datos que
usa el esquema de codificación DICOM.
Objeto de Información: una abstracción de una entidad verdadera de la
información (p.ej., CT la Imagen, el Estudio, etc.) que es interpretado por
uno o más comandos DICOM.
Clase de objeto de información: una descripción formal de un objeto de
información que incluye una descripción de su propósito y los atributos que
posee. No incluye los valores de estos atributos.
A.4.
Sı́mbolos y abreviaturas.
ACSE Association Control Service Element
CT Computed Tomography
DICOM Digital Imaging and Communications in Medicine
182
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
A.5. OBJETIVOS DEL ESTÁNDAR DICOM.
HIS Hospital Information System
NIU Network Interface Unit
OSI Open Systems Interconnection
PACS Picture Archiving and Communication Systems
RIS Radiology Information System
TCP/IP Transmission Control Protocol/Internet Protocol
A.5.
Objetivos del estándar DICOM.
El estándar DICOM facilita la interoperabilidad de dispositivos que
cumplen con éste. En particular:
Dirige la semántica de comandos y datos asociados. En dispositivos
que actúan recı́procamente, debe haber normas sobre cómo se espera
que estos dispositivos reaccionen a esas órdenes y esos datos asociados, no sólamente a cómo la información debe ser intercambiada entre
dispositivos.
Explicita en la definición de las exigencias de conformidad de las puestas en práctica del estándar. En particular, una declaración de conformidad debe especificar bastante información para determinar las
funciones para las que pueden esperar la interoperabilidad con otro
dispositivo reclamando la conformidad.
Facilita la operación en un ambiente conectado a una red, sin la exigencia de unidades de interfaz de red.
Está estructurado para acomodar la introducción de servicios nuevos,
facilitando ası́ el soporte para usos futuros de aplicaciones con
imágenes médicas.
Hace uso de normas existentes internacionales, y ellas mismas siguen
las directrices de documentación establecidas para normas internacionales.
Si bien el estándar DICOM tiene el potencial para facilitar las puestas en
práctica de soluciones PACS, el empleo del estándar sólo, no garantiza que
r
GVA-ELAI-UPMPFC0074-03
183
APÉNDICE A. ESTÁNDAR DICOM PARTE 1
José Ma Onrubia
todos los objetivos de un PACS sean cumplidos.
El estándar facilita la interoperabilidad de sistemas siguiendo la conformidad en un ambiente de multivendedor, pero por sı́ mismo no garantiza la
interoperabilidad. Ha sido desarrollado con énfasis en el diagnóstico médico
como el practicado en radiologı́a y en disciplinas relacionadas; sin embargo,
se piensa que también es aplicable a una amplia gama de información de
imágenes relacionadas en los ambiente clı́nicos.
A.6.
Contenido del estándar DICOM.
A.6.1.
Estructura del documento.
DICOM la versión 3.0 consiste en el siguiente nueve partes:
PS 3.1: Introducción y descripción
PS 3.2: Conformidad
PS 3.3: Definiciones de objeto de información
PS 3.4: Datos especı́ficos de clase de Servicio
PS 3.5: Estructura de datos y Codificación
PS 3.6: Diccionario de datos
PS 3.7: Intercambio de mensajes
PS 3.8: Soporte de comunicación en red para el intercambio de mensajes
PS 3.9: Soporte de comunicación puntop por punto para el intercambio
de mensajes
Estas partes del estándar están relacionadas, pero son documentos independientes. Una corta descripción de las Partes 2 a 9 se proporcionan en
esta sección.
A.6.2.
PS 3.2: Conformidad
PS 3.2 del Estándar DICOM define principios que las implementaciones
deben seguir:
184
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
A.6. CONTENIDO DEL ESTÁNDAR DICOM.
Exigencias de conformidad. PS 3.2 especifica las exigencias generales
que deben ser encontradas por cualquier realización. Hace referencia a
secciones de conformidad de otras partes del estándar.
Declaración de conformidad. PS 3.2 define la estructura de un estado
de conformidad. Especifica la información que debe estar presente en
una declaración de conformidad. Hace referencia a las secciones del
estado de conformidad de otras partes del estándar.
PS 3.2 no especifica procedimientos de pruebas y validación para evaluar
la conformidad de una implementación del estándar. La figura representa el proceso de construcción para una declaración de conformidad. Una
declaración de conformidad consiste en tres partes principales:
el conjunto de los objetos de información que son reconocidos por esta
implementación
el conjunto de las clases de servicio que es reconocido en ésta implementación.
el conjunto de los protocolos de comunicaciones que esta implementación soporta.
r
GVA-ELAI-UPMPFC0074-03
185
APÉNDICE A. ESTÁNDAR DICOM PARTE 1
A.6.3.
José Ma Onrubia
PS 3.3: Definiciones de objetos de la información
(IOD´s)
PS 3.3 del estándar DICOM especifica unas clases de objeto de información que proporcionan una definición abstracta de entidades del mundo
real, aplicables a la comunicación de imágenes digitales médicas. Cada IOD
consiste en la descripción de su objetivo y los atributos que lo definen. Un
IOD no incluye los valores para los atributos que comprenden su definición.
Para facilitar el crecimiento futuro del estándar y mantener la compatibilidad con las versiones anteriores del estándar, dos tipos de IOD´s están
definidos: normalizado y compuesto.
Los IOD´s normalizados incluyen sólo aquellos atributos inherentes a la
entidad de mundo real representada. Por ejemplo, la clase de objeto de
186
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
A.6. CONTENIDO DEL ESTÁNDAR DICOM.
información de estudio, que está definida como normalizado, contiene los
atributos de los estudios de fecha y tiempo porque son inherentes al estudio
actual. El nombre del paciente, sin embargo, no es un atributo de la clase
de objeto de información de estudio porque ésto, es inherente al paciente
sobre el que el estudio ha sido realizado y no sobre el estudio en sı́ mismo.
Las clases de objeto de información compuestas pueden además incluir
los atributos que tienen relación, pero que no son inherentes a la entidad
del mundo real. Por ejemplo, la clase de objeto de información de imagen
de tomográfica calculada, que está definida como compuesta, contiene los
atributos que son inherentes a la imagen (p.ej. la fecha de imagen) y los
atributos que están relacionados, pero que no son inherentes a la imagen
(p.ej. el nombre paciente). Las clases de objeto de información compuestas
proporcionan un marco estructurado para expresar las exigencias de comunicación de las imágenes que han sido definidos en las versiones anteriores
del estándar.
Para simplificar las definiciones de clase de objeto de información,
los atributos de cada clase de objeto de información están divididos en
atributos similares, agrupados juntos. Estas agrupaciones de atributos son
especificadas como módulos independientes y pueden ser reutilizadas por
una o más clases de objeto de información compuestas.
Para representar un acontecimiento de una entidad del mundo real, se
crea una instancia de objeto de información, en la cual se incluyen valores
para los atributos de la clase de objeto de información. Los valores de
atributo de esta instancia de objeto de información pueden cambiar con
tiempo para reflejar con exactitud el estado que se cambia de la entidad a la
que esto representa. Ésto se logra realizando operaciones básicas diferentes
sobre la instancia de objeto de información para dar un juego especı́fico de
servicios definidos como una clase de servicio. Estas clases de servicio son
definidas en PS 3.4 del Estándar.
PS 3.3 también está relacionado con otras partes del estándar DICOM:
PS 3.5, Estructura de datos y semántica, define la estructura del conjunto de datos y la codificación para convey DICOM Information Object Attributes
PS 3.6, Dicconario de datos, define la semántica de los elementos de
datos DICOM la cual tranporta los atributos de objetos de información
definidos en PS 3.3.
r
GVA-ELAI-UPMPFC0074-03
187
APÉNDICE A. ESTÁNDAR DICOM PARTE 1
A.6.4.
José Ma Onrubia
PS 3.4: Especificaciones de las clases de servicio.
PS 3.4 del estándar DICOM define un número de clases de servicio. Una
clase de servicio asocia uno o más objetos de información con una o más
órdenes para ser realizadas sobre estos objetos.
PS 3.4 del estándar DICOM define las caracterı́sticas compartidas por
todas las clases de servicio, y como una declaración de conformidad a
una clase de servicio individual está estructurada. Contiene unos anexos
normativos que describen clases de servicio individuales detalladamente.
Los ejemplos de Clases de Servicio incluyen lo siguiente:
Clase de servicio de almacenamiento.
Clase de servicio de pregunta.
Clase de servicio de recuperación.
Clase de servicio de gestión de estudio.
PS 3.4 define las operaciones realizadas sobre los objetos de información
definidos en PS 3.3. PS 3.7 define las órdenes y protocolos para usar los
comandos para lograr las operaciones descritas en PS 3.4.
A.6.5.
PS 3.5: Estructura de datos y semántica
PS 3.5 del estándar DICOM especifica como las entidades de aplicación
DICOM construyen y codifican la información de conjunto de datos el
siendo resultado del empleo de los objetos de información y clases de
servicios definidas en las partes 3 y 4 del estándar DICOM.
PS 3.5 del estándar DICOM, especifica como entidades de aplicación
DICOM construyen y codifican la información del conjunto de datos, siendo
conjunto el resultado del empleo de los objetos de información y clases de
servicios definidas en las partes 3 y 4 del estándar DICOM.
PS 3.5 direcciona las reglas de codificación necesarias para construir un
flujo de datos para ser transportada en un mensaje como se especifica en
PS 3.7 del estándar DICOM. Estos datos son producidos de la colección de
elementos de datos que forman el conjunto de datos. Varios conjuntos de
datos pueden ser referidos o doblados en un conjunto de datos compuesto.
Un conjunto de datos compuesto es usado para transferir en ün paquete”el
188
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
A.6. CONTENIDO DEL ESTÁNDAR DICOM.
contenido de objetos de información, ofreciendo una capacidad de carpeta.
PS 3.5 también define la semántica de un número de unas funciones
genéricas que son comunes a muchos objetos de información.
A.6.6.
PS 3.6: Diccionario de datos
PS 3.6 del estándar DICOM es el registro centralizado que define la colección de todos los elementos de datos DICOM disponibles para representar
la información. Para cada elemento de datos, PS 3.6:
asigna una etiqueta única, que consiste en grupo y el número de elemento
le da un nombre
especifica sus caracterı́sticas de valor (la cadena de caracteres, el
número entero, etc.)
define su semántica (como debe ser interpretado).
PS 3.6, en la conjunción con PS 3.5, es usado para construir conjunto de
datos, y representar objetos de información como conjuntos de datos en la
conjunción con PS 3.3 Y PS 3.5.
A.6.7.
PS 3.7: Intercambio de mensajes.
PS 3.7 del estándar DICOM especifica tanto el servicio como el protocolo
usado por una entidad de aplicación en un ambiente de imágenes médicas
para intercambiar mensajes sobre los servicios de apoyo de comunicaciones
definidos en PS 3.8 O PS 3.9. Un mensaje está compuesto por un flujo de
órdenes definidos en PS 3.7 seguido por un flujo de datos opcional como lo
definido en PS 3.5.
Esta parte especifica lo siguiente:
reglas para establecer y finalizar las asociaciones proporcionadas por
el apoyo de comunicaciones especificado en PS 3.8 O PS 3.9, y las
repercusiones sobre transacciones excepcionales.
reglas que gobiernan el intercambio de peticiones y respuestas de
órdenes.
r
GVA-ELAI-UPMPFC0074-03
189
APÉNDICE A. ESTÁNDAR DICOM PARTE 1
José Ma Onrubia
reglas codificadas necesarias para construir flujo de órdenes y mensajes.
Además, PS 3.7 está relacionado con otras partes del estándar:
PS 3.3, las definiciones de objeto de información, especifican el juego
de clases de objeto de información a las que las Órdenes definidas en
PS 3.7 pueden ser aplicadas.
PS 3.5, la estructura de datos y la semántica, dirigen las reglas de
codificación necesarias para construir un flujo de datos para ser transportada en un mensaje especificado en PS 3.7 del estándar DICOM.
PS 3.7, el intercambio de mensajes, define las órdenes y protocolos
para usar las órdenes para lograr las operaciones descritas en PS 3.4.
A.6.8.
PS 3.8: Apoyo de comunicación de red para el intercambio de mensaje
PS 3.8 del estándar DICOM especifica los servicios de comunicación y
los protocolos de capas superiores necesarios para soportar, en una red, la
comunicación entre entidades de aplicación DICOM según lo especificado
en PS 3.3, PS 3.4, PS 3.5, PS 3.6, Y PS 3.7. Estos servicios de comunicación
y protocolos aseguran que la comunicación entre entidades de aplicación
DICOM sea realizada de una manera eficiente y coordinada a través de la
red.
Los servicios de comunicación especificados en PS 3.8 son un subconjunto
apropiado de los servicios ofrecidos por el servicio de presentación OSI (LA
ISO 8822) y del elemento de servicio de control de asociación OSI (ACSE)
(LA ISO 8649). Se refieren al servicio de capa superior, que permite a un
par entidades de aplicación el establecimiento de asociaciones, mensajes de
transferencia y el fin de las asociaciones.
Esta definición del servicio de capa superior permite el empleo de los
protocolos OSI (Capas 1 a 6 más ACSE) para alcanzar una comunicación
robusta y eficiente. Ésto, soporta una gran variedad de estándares internacionales basados en tecnologı́as de red que usan una amplia opción de redes
fı́sicas como la ISO 8802-3 CSMA/CD (Ethernet a menudo llamada), FDDI,
ISDN, X.25, dedicated digital circuits y muchas otras LAN y tecnologı́as de
red WAN.
Además, este mismo servicio de capa superior también puede ser proporcionado por el protocolo de capa DICOM superior usado conjuntamente
190
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
A.6. CONTENIDO DEL ESTÁNDAR DICOM.
con protocolos de transporte de TCP/IP. Por lo tanto, una amplia gama
de ambientes de red se pueden usar. La definición de un servicio de capa
superior común a OSI y a ambientes TCP/IP, permite la migración de un
TCP/IP a un ambiente OSI sin chocar entidades de aplicación DICOM.
Estos protocolos de comunicación especificados por PS 3.8 son protocolos
de comunicación de objetivos generales (OSI, TCP/IP) y no versiones
especı́ficas para el estándar DICOM. La figura muestra estos dos protocolos.
A.6.9.
PS 3.9: Soporte de comunicación para el intercambio
de mensajes punto por punto.
El PS 3.9 del estándar DICOM especifica los servicios y los protocolos usados para las comunicaciones punto por punto de una manera compatible con
ACR-NEMA 2.0. Especifica un interfaz fı́sico y protocolos señalados. Define
r
GVA-ELAI-UPMPFC0074-03
191
APÉNDICE A. ESTÁNDAR DICOM PARTE 1
José Ma Onrubia
el OSI enlace para transmisión de datos y protocolos sesión/transporte/red y
los servicios del montón de protocolo para ser usado sobre este interfaz fı́sico.
Los servicios de capa de sesión/transporte/red especificados y protocolos
soportan la comunicación entre entidades de aplicación DICOM como lo
especificado en las partes 3, 4, 5, 6, y 7. Estos servicios son un subconjunto
de los servicios de capa superiores especificados en PS 3.8 del estándar
DICOM. Esta caracterı́stica del subconjunto permite la interconexión de
un dispositivo con un interfaz de punto-punto a un ambiente de comunicación totalmente conectado a una red con soporte OSI Y TCP/IP. Tal
interconexión requiere una unidad de interfaz de red interventor (NIU). La
figura presenta como un interfaz de punto-punto y un ambiente conectado
a una red coexisten.
192
r
GVA-ELAI-UPMPFC0074-03
José Ma Onrubia
A.7. RELACIONES ENTRE LAS PARTES DEL ESTÁNDAR.
A.7.
Relaciones entre las partes del estándar.
Las relaciones siguientes existen entre las partes del estándar:
PS 3.1: la introducción y la descripción describen la estructura total del
estándar.
PS 3.2: la conformidad especifica las exigencias generales que deben
ser encontradas por puestas en práctica reclamando la conformidad y el
contenido de una Declaración de conformidad.
PS 3.3: las definiciones de objeto de información especifican la estructura
y los atributos de los objetos que son manejados por clases de servicio (PS
3.4). Estos objetos incluyen imágenes, estudios, y pacientes.
PS 3.4: los datos especı́ficos de clase de servicio definen las operaciones
que pueden ser realizadas sobre los casos de objetos de información (PS
3.3) para proporcionar un servicio especı́fico. Estos servicios incluyen el
almacenaje de imagen, la recuperación, y la impresión.
PS 3.5: la estructura de datos y la Semántica especifican la codificación
del contenido de datos de los mensajes que son cambiados para lograr las
operaciones usadas por las clases de servicio (PS 3.4).
PS 3.6: el diccionario de datos define los atributos individuales de la
información que representan el contenido de datos (PS 3.5) de los casos de
objetos de información.
PS 3.7: el cambio de mensaje especifica las operaciones y el protocolo
usado para cambiar mensajes. Estas operaciones son usadas para lograr los
servicios definidos por las clases de servicio (PS 3.4).
PS 3.8: el apoyo de comunicación de red para el cambio de mensaje
define los servicios y protocolos usados para cambiar mensajes (PS 3.7)
directamente sobre REDES de TCP/IP y OSI.
PS 3.9: el apoyo de comunicación punto a punto para el intercambio de
mensajes define los servicios y los protocolos usados para el intercambio de
mensajes (PS 3.7) en la interfaz de 50 pines.
Para más imformación dirigirse a la parte del estándar deseada. Todas
las partes del estándar se pueden encontrar en la red.
r
GVA-ELAI-UPMPFC0074-03
193
APÉNDICE A. ESTÁNDAR DICOM PARTE 1
194
José Ma Onrubia
r
GVA-ELAI-UPMPFC0074-03
Índice de figuras
2.1.
2.2.
2.3.
2.4.
2.5.
2.6.
4
6
7
8
9
Proceso distribuido . . . . . . . . . . . . . . . . . . . . . . . .
Modelo de un proceso distribuido . . . . . . . . . . . . . . . .
Clases de servicio DICOM . . . . . . . . . . . . . . . . . . . .
Relaciones entre IODs y atributos . . . . . . . . . . . . . . .
Ejemplo de una imagen IOD compuesta. . . . . . . . . . . . .
Descripción de la codificación y decodificación de las instancias SOP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.7. DICOM con intercambio en red. . . . . . . . . . . . . . . . .
2.8. Capas OSI . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.9. Conexión TCP . . . . . . . . . . . . . . . . . . . . . . . . . .
2.10. Estatuto de conformidad con perfil del sistema. . . . . . . . .
2.11. Estatuto de conformidad con perfil de aplicación . . . . . . .
2.12. Diferentes partes del estándar DICOM . . . . . . . . . . . . .
2.13. Del mundo real al modelo de información . . . . . . . . . . .
2.14. Ejemplo de ”mapping”de un CT . . . . . . . . . . . . . . . .
2.15. Modelo de información de una imagen compuesta DICOM . .
2.16. Clasificación de la información de la imagen . . . . . . . . . .
2.17. Juego básico de atributos de las instancias de imagen SOP . .
2.18. Ciclo de vida de Image SOP Instance Information . . . . . .
15
16
20
22
23
25
26
29
31
33
38
45
48
3.1.
3.2.
3.3.
3.4.
3.5.
Visual C++
Browser . .
Viewer . . .
Print . . . .
Process log
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
56
60
61
62
63
6.1.
6.2.
6.3.
6.4.
6.5.
6.6.
6.7.
Asistente para proyectos: paso 1
Partes de aplicación. . . . . . . .
contentPane . . . . . . . . . . . .
JScrollPane . . . . . . . . . . . .
constraints . . . . . . . . . . . .
JTextArea . . . . . . . . . . . . .
text . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
111
113
114
114
115
115
116
con DCMTK
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
.
.
.
.
.
.
.
.
.
.
195
.
.
.
.
.
ÍNDICE DE FIGURAS
José Ma Onrubia
6.8. Ejecutado . . . . . . . . . . . . . . . . . . . . . . . .
6.9. Menús . . . . . . . . . . . . . . . . . . . . . . . . . .
6.10. Editor . . . . . . . . . . . . . . . . . . . . . . . . . .
6.11. actionPerformed . . . . . . . . . . . . . . . . . . . .
6.12. jMenu . . . . . . . . . . . . . . . . . . . . . . . . . .
6.13. editor en negro . . . . . . . . . . . . . . . . . . . . .
6.14. API de JDK 1.4.1. . . . . . . . . . . . . . . . . . . .
6.15. Configurar JDK. . . . . . . . . . . . . . . . . . . . .
6.16. Nuevo camino de JDK. . . . . . . . . . . . . . . . . .
6.17. Propiedades de proyecto. . . . . . . . . . . . . . . . .
6.18. Propiedades de proyecto. . . . . . . . . . . . . . . . .
6.19. Propiedades de proyecto. . . . . . . . . . . . . . . . .
6.20. Estructura básica de la aplicación. . . . . . . . . . .
6.21. Panel Visor DICOM. . . . . . . . . . . . . . . . . . .
6.22. Zoom mediante botones Zoom In y Zoom Out. . . .
6.23. Zoom mediante cliqueos de ratón. . . . . . . . . . . .
6.24. Botones Anterior y Siguiente . . . . . . . . . . . . .
6.25. Botón Seguidas . . . . . . . . . . . . . . . . . . . . .
6.26. Botón Guardar JPEG . . . . . . . . . . . . . . . . .
6.27. Zona de insertar datos. . . . . . . . . . . . . . . . . .
6.28. Ver funcionamiento. . . . . . . . . . . . . . . . . . .
6.29. Botones para campos nuevos. . . . . . . . . . . . . .
6.30. Comprobar inserción de nuevo campo. . . . . . . . .
6.31. Panel Crear archivo DICOM. . . . . . . . . . . . . .
6.32. Imagen a insertar. . . . . . . . . . . . . . . . . . . .
6.33. Datos de texto a insertar. . . . . . . . . . . . . . . .
6.34. Comprobar la creación del archivo DICOM en escala
6.35. Comprobar la creación del archivo DICOM en color.
6.36. Resultados de nuestra secuencia. . . . . . . . . . . .
6.37. Panel procesamiento. . . . . . . . . . . . . . . . . . .
6.38. Botón para añadir archivos. . . . . . . . . . . . . . .
6.39. Botón para abrir imagen a procesar. . . . . . . . . .
6.40. Botón para procesar imagen. . . . . . . . . . . . . .
6.41. Panel Cliente/Servidor. . . . . . . . . . . . . . . . .
6.42. Asistente creador de recopilatorios. . . . . . . . . . .
6.43. Asistente creador de recopilatorios. Paso2. . . . . . .
6.44. Asistente creador de recopilatorios. Paso3. . . . . . .
196
. . . . . 117
. . . . . 117
. . . . . 119
. . . . . 120
. . . . . 122
. . . . . 125
. . . . . 133
. . . . . 138
. . . . . 139
. . . . . 140
. . . . . 141
. . . . . 142
. . . . . 143
. . . . . 144
. . . . . 146
. . . . . 147
. . . . . 149
. . . . . 150
. . . . . 151
. . . . . 153
. . . . . 155
. . . . . 156
. . . . . 157
. . . . . 159
. . . . . 160
. . . . . 161
de grises.163
. . . . . 164
. . . . . 167
. . . . . 168
. . . . . 170
. . . . . 171
. . . . . 171
. . . . . 172
. . . . . 174
. . . . . 174
. . . . . 175
r
GVA-ELAI-UPMPFC0074-03