Cualquiera que haya movido un archivo de estudios entre fabricantes de PACS, cambiado una modalidad o validado una cadena de anonimización se ha enfrentado a la misma pregunta: ¿son iguales estos dos archivos DICOM y, si no, en qué difieren exactamente? Es una pregunta fácil de formular y sorprendentemente incómoda de responder, porque un archivo DICOM no es una lista plana de valores, sino un conjunto de datos anidado donde el mismo contenido clínico puede codificarse de formas materialmente distintas.
Qué contiene realmente un conjunto de datos DICOM
Un archivo DICOM combina una cabecera de metainformación con un conjunto de datos de atributos. Cada atributo se identifica con una etiqueta escrita como número de grupo y elemento, por ejemplo (0010,0010) para el nombre del paciente. Junto a la etiqueta va una Value Representation, o VR: un código de dos letras que declara el tipo de dato —PN para un nombre de persona, DA para una fecha, UI para un identificador único, SQ para una secuencia, etc.—. El VR determina tanto cómo se interpretan los bytes como qué aspecto tiene un valor válido.
Comparar dos archivos significa por tanto emparejar atributos por etiqueta y luego comparar valores dentro del tipo que declara el VR. Una comparación de archivos a nivel de byte es aquí casi inútil: dos archivos con contenido clínico idéntico diferirán en bytes si usan sintaxis de transferencia distintas, si el orden de los atributos varía o si el relleno es diferente.
Secuencias: donde fallan las comparaciones planas
El atributo con VR SQ es el que rompe las herramientas simples. Una secuencia contiene una lista ordenada de elementos, y cada elemento es a su vez un conjunto de datos anidado completo que puede contener más secuencias. La Scheduled Procedure Step Sequence (0040,0100), la Referenced Image Sequence (0008,1140) y los árboles de contenido profundamente anidados del DICOM Structured Reporting viven todos dentro de secuencias.
Una comparación que solo informe "(0040,0100): secuencia con 2 elementos" en ambos lados no te dice nada sobre si la modalidad, la descripción programada o el médico responsable dentro de esos elementos han cambiado. Como el orden de los elementos es significativo dentro de una secuencia, una comparación correcta empareja el elemento 1 con el elemento 1, desciende en cada uno y compara los atributos que hay allí, que es lo que hace esta herramienta, informando de cada atributo anidado con su ruta completa para que veas en qué punto del árbol vive la diferencia.
Qué cambia legítimamente en una migración
No toda diferencia es un defecto. Entender qué cambios son esperables es la mayor parte del trabajo de validar una migración:
- Sintaxis de transferencia y codificación. Un archivo de destino puede almacenar los objetos con otra sintaxis de transferencia, cambiando cómo se codifican los valores sin cambiar lo que significan. El caso habitual es VR explícito frente a implícito.
- Identidad de la implementación. Implementation Class UID (0002,0012) e Implementation Version Name (0002,0013) identifican el software que escribió el archivo, así que cambian legítimamente siempre que otro sistema escribe el objeto.
- Coerción de identificadores. Muchos archivos coercionan Patient ID, Accession Number o Study ID para ajustarlos al índice maestro de pacientes de la institución receptora. Es un comportamiento intencionado y configurado, y es justo lo que necesitas verificar que ocurrió correctamente.
- Marcas de tiempo de transferencia. Los atributos que registran cuándo se recibió o archivó un objeto diferirán por diseño.
Lo que en general no debería cambiar en una migración directa es el contenido clínico: los atributos que definen el píxel, como Rows, Columns, Bits Allocated y Photometric Interpretation, los atributos de geometría que permiten reconstruir correctamente las imágenes, y la identidad de instancia que vincula las imágenes con su serie y su estudio.
Los UID: los atributos que merecen su propio filtro
Los identificadores únicos —atributos con VR UI— son la columna vertebral del modelo de información de DICOM. Study Instance UID, Series Instance UID y SOP Instance UID forman la jerarquía que permite a un archivo ensamblar instancias sueltas en un estudio coherente. Si rompes esa jerarquía, las imágenes se dispersan por estudios equivocados o desaparecen de la lista de trabajo.
Aquí tiran dos reglas en direcciones opuestas, y por eso el filtro de UID resulta útil. En una migración directa, los UID de instancia deben conservarse exactamente, porque son la identidad del objeto; un SOP Instance UID cambiado significa que el archivo ha creado un objeto nuevo en lugar de mover el existente. En la anonimización, por el contrario, los UID por lo general deben sustituirse, porque un UID conservado enlaza la copia anonimizada con el estudio original. Filtrar el diff por VR UI responde a "¿sobrevivieron los UID?" o "¿se regeneraron los UID?" en una sola vista, según cuál de las dos operaciones estés validando.
Validar la anonimización
Cuando el segundo archivo pretende ser una copia anonimizada del primero, el diff se convierte en un informe de verificación. Lo que quieres ver es que todos los atributos de la lista de PHI han cambiado —eliminados, vaciados o sustituidos— y que los atributos clínicos no.
Filtrar por etiquetas PHI te da exactamente esa vista. Cualquier atributo PHI que siga apareciendo como idéntico es una fuga que conviene investigar: un nombre de paciente, una fecha de nacimiento, un nombre de institución o un médico solicitante que sobrevivió a la anonimización. La comprobación inversa también importa: si un atributo clínicamente relevante aparece como cambiado cuando no debería haberlo hecho, el perfil de anonimización es más agresivo de lo previsto y puede haber dañado el valor diagnóstico del conjunto de datos.
El anexo E de DICOM PS3.15 define perfiles de confidencialidad que especifican exactamente qué atributos deben tratarse y cómo. Un diff no sustituye a leer esa especificación, pero es la forma más rápida de contrastar una cadena de proceso con ella sobre archivos reales y no en teoría.
Leer un diff sin ahogarse
Una cabecera de TC típica lleva unos cientos de atributos, y un objeto multiframe mejorado o un informe estructurado pueden llevar miles una vez expandidas las secuencias. Mostrarlo todo rara vez es útil, y por eso la vista de solo diferencias viene activada por defecto.
Un orden de trabajo práctico: empieza por solo diferencias y mira el recuento del resumen. Si la cifra es pequeña, lee todas las filas. Si es grande, aplica primero el filtro de UID para confirmar que los atributos de identidad se comportaron como exige la operación, después el filtro de PHI para confirmar el comportamiento de confidencialidad, y luego acota por VR para barrer categorías: DA y TM para fechas y horas, PN para nombres, CS para valores codificados. Busca por número o nombre de etiqueta cuando tengas un atributo concreto en mente. Exporta las filas filtradas como CSV cuando la vista muestre exactamente lo que el ticket necesita registrar.
Los límites de un diff de cabecera
Una comparación a nivel de etiqueta es una comparación de cabecera y metadatos. Te dirá que Rows, Columns y Bits Allocated coinciden, lo cual es un indicio sólido de que los datos de píxel están estructuralmente intactos, pero no decodifica ni compara los píxeles en sí. Una migración que conservara todos los atributos de cabecera mientras corrompe o transcodifica los datos de imagen mostraría un diff limpio.
Por eso un diff de cabecera pertenece a una batería de validación junto a una comprobación a nivel de píxel y una revisión visual de una muestra representativa, no en su lugar. Es la forma más rápida de encontrar las diferencias que una cabecera puede expresar, y guarda silencio deliberadamente sobre las que no puede.