lundi 8 octobre 2018

Les images en DICOM - Partie 2

Cet article constitue la seconde partie consacrée aux images dans DICOM.
Dans la première partie, nous avons parlé des images dites « natives », c'est-à-dire qui n'utilisent pas de technique de compression.
Ce billet est consacré aux images dites « encapsulées », c'est-à-dire qu'elles utilisent des techniques de compression pour encoder les pixels des images.
Le but des techniques de compression est d'économiser de l'espace si l'objet DICOM est stocké sur un support physique, ou de gagner du temps lors du transfert d'un objet DICOM via un réseau.

Le thème des techniques de compression dans DICOM est assez vaste. C'est pourquoi ce sujet est décomposé en deux sous-parties :
  • La compression et l'encodage en DICOM ;
  • Les syntaxes de transfert & les différents schémas de compression adoptés par DICOM.
Ce billet parle de la première sous-partie.

1. La Compression


Compresser une image, ou de manière plus générale des données, consiste à appliquer une transformation sur ces données pour en réduire la taille. Une fois cette opération effectuée, il n'est alors en général plus possible de les lire (un peu comme si elles étaient cryptées, sauf qu'ici, le but premier n'est pas de rendre illisible les données, mais d'en réduire la taille). Pour pouvoir interpréter de nouveau les données, il faut appliquer la transformation inverse.

La transformation pour réduire la taille des données est appelée « compression ». À l'inverse, la transformation pour retrouver les données lisibles s'appelle la « décompression ».
Pour compresser des données, on utilise un compresseur et pour les décompresser, on utilise un décompresseur.

Il faut donc un binôme Compresseur/ Decompresseur (appelé CoDec) pour réduire la taille des données puis les lire de nouveau.

Avec le développement des différentes techniques de compression, deux catégories se sont imposées.
  • La compression réversible (ou compression sans perte) ;
  • La compression irréversible (ou compression avec perte).
Pour illustrer le principe général de ces deux familles, reprenons le très bon exemple issu du livre « DICOM, A Practical Introduction and Survival Guide » d'Oleg S. Pianykh.

1.1 Compression sans perte


La compression sans perte permet de ne pas changer des données. Ainsi, une fois l'opération de compression et de décompression effectuée, les données sont les mêmes que si aucune transformation n'avait été appliquée.

Pour avoir une idée générale de comment il est possible d'effectuer une compression sans perte, prenons l'exemple suivant:

Supposons que l'on dispose de la suite de valeur de pixels suivante:

1000, 1001, 1002, 1002, 1000, 1000, 1001, 1057, ...

Un algorithme de compression sans perte pourrait être d'exploiter la répétitivité de la valeur la plus fréquente en la remplaçant par quelque chose de plus court. Par exemple, remplacer la chaîne « 1000 » par le caractère « a ». On obtiendrait donc :

a, 1001, 1002, 1002, a,  a, 1001, 1057, ...

La chaîne « a » étant plus courte que la chaîne « 1000 », la longueur globale est donc plus petite.
Il est toujours possible de décompresser le résultat et retrouver la suite originale en remplaçant les « a » par « 1000 ».

Remarque: Le codage de Huffman ou le Run Length Encoding (RLE) sont des exemples d'algorithmes de compression sans perte.

1.2 Compression avec perte


La compression avec perte va sacrifier des données pour obtenir un meilleur taux de compression. Ainsi, une fois l'opération de compression et de décompression effectuée, les données retrouvées ne sont pas les mêmes que les données originales.

Prenons deux couleurs très similaires dont les valeurs RGB sont:
Ces deux couleurs peuvent sembler identiques visuellement car le changement est tellement petit que l’œil humain n'arrive pas à les distinguer.  Une technique de compression avec perte est de jouer sur ces petits changements imperceptibles.

Reprenons la suite de valeurs de pixels ci-dessus:

1000, 1001, 1002, 1002, 1000, 1000, 1001, 1057, ...

« 1000 » et « 1001 » sont très proches. Tellement proches que la différence est négligeable. Nous allons donc remplacer la chaîne « 1001 » par « 1000 ».
On obtient donc:

1000, 1000, 1002, 1002, 1000, 1000, 1000, 1057, ...

En appliquant le même algorithme de compression sans perte que ci-dessus (remplacer « 1000 » par « a »), on obtient la suite :

a, a, 1002, 1002, a, a, a, 1057, ...

Le résultat est donc encore plus court que précédemment (meilleur taux de compression). En revanche en décompressant cette suite, nous sommes incapable de dire quel « a » représentait un « 1000 » et quel autre « a » représentait un « 1001 ». Une fois décompressé, la suite est différente de l'originale (même si visuellement aucune différence n'est notable). En finalité, nous avons donc perdu (sacrifié) des données pour une meilleure compression.

Remarque: La transformée en cosinus discrète (TCD) est un exemple d'algorithme de codage avec perte. Il est utilisé par JPEG (et par DICOM) pour sacrifier des données et obtenir un meilleur taux de compression (cf. PS3.5 Annexe F.1).

Conseil: Le format d'image BMP par exemple est non destructeur alors que le format JPEG est quant à lui destructeur (sacrifice de données). C'est pourquoi, il est préférable de travailler sur une image BMP et de l'enregistrer en JPEG à la fin, plutôt que de travailler sur une image en JPEG et qu'à chaque enregistrement (pour sauvegarder les changements de manière périodique) on dégrade un peu plus l'image.

3. Encodage d'une image en DICOM


Les tags évoqués dans la première partie sont toujours valables. La seule contrainte est que ces derniers soient cohérent par rapport à l'image (voir remarque ci-dessous). Seul l'utilisation du tag (7FE0, 0010) Pixel Data change. La description détaillé de cet élément DICOM est décrite dans la partie PS3.5 Annexe A.4 du standard.

Remarque: Les valeurs mentionnées dans les éléments de données spécifiant l'encodage d'une image (Photometric Interpretation, Samples per Pixel, Planar Configuration, Bits Allocated, Bits Stored, High Bit, Pixel Representation, Rows, Colums, etc.) doivent être cohérents avec ceux qui apparaissent dans le flux d'octets de l'image compressée. Toutefois, en cas d'inconsistance, il est recommandé que le processus de décodage utilise les paramètres mentionnés dans le flux d'octets représentant les données compressées.

3.1. Généralité


Lorsque l'on utilise une technique de compression (avec ou sans perte) pour stocker les pixels d'une image, le standard indique que l'encodage DICOM doit toujours se faire en Little Endian et en Explicit VR (cf. PS3.5 - Annexe A.4).

3.2. Pixel Data


Comme pour les images natives, le tag (7FE0, 0010) Pixel Data permet de stocker les pixels d'une ou plusieurs images. Il existe néanmoins des contraintes sur cet élément pour les images encapsulées:
  • La VR doit être « OB » (Other Bytes). Il n'est pas possible d'utiliser une VR de type « OW » (Other Words) ;
  • Pixel Data doit contenir le flux d'octet exprimant l'image compressée (entête comprise) ;
  • Contrairement aux images natives qui stockent directement les pixels dans l'élément (7FE0, 0010) Pixel Data, il faut impérativement utiliser une séquence DICOM pour stocker les pixels compressés (d'où le nom « Encapsulated Image »). De plus, la séquence doit respecter les contraintes suivantes:
    • L'encodage de la séquence doit se faire en « Undefined Length » ;
    • Le premier élément de la séquence doit être une « Basic Offset Table » ;
    • Les autres éléments de la séquence sont les pixels de l'image (ou des images dans le cas d'une Multi-frame).
Autre point important, une image peut être fragmentée en plusieurs parties. Chacune de ces dernières faisant l'objet d'un item de la séquence.

Quelques mots sur la fragmentation d'image : Une image peut être entièrement contenue dans un item, ou être divisée dans plusieurs parties. Cette fragmentation permet de supporter la bufferisation pendant la compression d'une image ou d'éviter de dépasser la taille maximum d'un fragment. Un logiciel voulant lire une image DICOM peut détecter la fragmentation d'une image en comparant le nombre de fragments (nombre d'items -1 pour la Basic Offset Table) avec le nombre d'images (tag (0028,0008) Number of Frames).

Remarque: Les tags (7FE0,0008) Float Pixel Data et (7FE0,0009) Double Float Pixel Data ne peuvent pas être utilisés pour stocker des images compressées. Ces deux Data Element ne peuvent stocker que des données au format Natif (cf. PS3.5 - section 8.2).

3.2.1 L'item Basic Offset Table (premier item de la séquence)


Cet item est obligatoire, mais sa valeur est optionnelle. Si la valeur est présente, elle contient, pour chaque image, l'offset du premier octet du premier fragment (item) de chacune des images. L'offset est calculé à partir du premier octet du premier item après la Basic Offset Table. Chaque offset est codé sur 32 bits (4 octets).

Remarque: Lorsque la valeur n'est pas présente, la longueur de l'item doit être 0000H.

Des exemples sont disponibles dans la section 3.2.3. ci-dessous.

3.2.2 Les autres items (suivant le premier item)


L'encodage de chaque item se fait en « Explicit Length » et de la manière suivante:
  • Le champ « Tag » doit avoir la valeur (FFFE, E000) ;
  • Le champ « Length » de 4 octets doit contenir le nombre d'octets contenu dans le champ « Value » ;
  • Le champ « Value » contient le flux d'octets (ou une partie du flux d'octets) représentant l'image compressée ;
  • Le champ « Value » doit toujours avoir une longueur paire. La valeur peut donc être complétée par le caractère NULL (cf. L'encodage d'objet DICOM - Format Classique (Partie 1)).

3.2.3 Exemples d'encodage d'une séquence


3.2.3.1. Exemple d'encodage d'une image (single frame) définie avec une séquence de trois fragments sans Basic Offset Table

Tag VR Longueur Valeur
(7FE0, 0010)
avec une VR
de OB
OB 0000H
Réservé
FFFF FFFFH
longueur indéfinie
Basic Offset Table SANS Valeur 1er Fragment (Single Frame) des pixels
Tag Longueur Tag Longueur Valeur
(FFFE, E000) 0000 0000H (FFFE, E000) 0000 04C6H Fragment Compressé
4 octets 2 octets 2 octets 4 octets 4 octets 4 octets 4 octets 4 octets 04C6H octets

Suite de la séquence (Valeur)
2d Fragment (Single Frame) de pixels 3ème Fragment (Single Frame) de pixels Sequence Delimiter Item
Tag Longueur Valeur Tag Longueur Valeur Sequence Delim. Tag Longueur
(FFFE, E000) 0000 024AH Fragment Compressé (FFFE, E000) 0000 0628H Fragment Compressé (FFFE,  E0DD) 0000 0000H
4 octets 4 octets 024AH octets 4 octets 4 octets 0628H octets 4 octets 4 octets

C.2.3.2. Exemple d'encodage d'une Multi-frame de 2 images définie avec une séquence de trois fragments avec Basic Offset Table

Tag VR Longueur Valeur
(7FE0, 0010)
avec une VR
de OB
OB 0000H
Réservé
FFFF FFFFH
longueur indéfinie
Basic Offset Table AVEC Valeur 1er Fragment (Frame 1) de pixels
Tag Longueur Valeur Tag Longueur Valeur
(FFFE, E000) 0000 0008H 0000 0000H
0000 0646H
(FFFE, E000) 0000 02C8H Fragment
Compressé
4 octets 2 octets 2 octets 4 octets 4 octets 4 octets 0008H octets 4 octets 4 octets 02C8H octets

Suite de la séquence (Valeur)
2d Fragment (Frame 1) de pixels 3ème Fragment (Frame 2) de pixels Sequence Delimiter Item
Tag Longueur Valeur Tag Longueur Valeur Sequence Delimiter Tag Longueur
(FFFE, E000) 0000 036EH Fragment
Compressé
(FFFE, E000) 0000 0BC8H Fragment
Compressé
(FFFE, E0DD) 0000 0000H
4 octets 4 octets 036EH octets 4 octets 4 octets 0BC8H octets 4 octets 4 octets

Remarque: DICOM autorise l'encodage (la compression) des pixels d'une image dans certains formats. Par exemple, il n'est pas possible d'utiliser les formats PNG ou ZIP, mais il est possible d'utiliser les formats JPEG et RLE. Ces formats sont décrits dans la seconde sous-partie consacrée à la compression des images en DICOM.

4. Exemples de fichiers

5. Quelques remarques sur l'imagerie médicale et la compression

  • Le standard DICOM ne donne aucune indication sur comment utiliser les différentes compressions disponibles. C'est en effet en dehors du périmètre du standard. De plus, beaucoup trop de paramètres entrent en jeux pour indiquer quelle compression utiliser sur telle ou telle image (type d'image, qualité de l'image, etc.). Malgré cette absence d'indication dans le standard, une règle de bonne pratique est que quelque soit le schéma de compression, il est déconseillé d'utiliser un codec propriétaire pour l'archivage. Cela pourrait mener à des problèmes d'interopérabilités et de migrations.
  • Il y a souvent une incompréhension sur la taille des fichiers DICOM lorsque ces derniers sont encapsulés. En effet, ce n'est pas parce qu'un fichier fait 30 Mo que cela indique qu'une fois chargée en mémoire, l'image fera effectivement 30 Mo. Si le ratio de compression et de 10:1. Alors une fois décompressée, l'image fera 300 Mo. Charger une série ou un examen DICOM en entier peut vite mettre à genoux un ordinateur si celui est sous dimensionné.
  • Autre point important, ce n'est pas parce que l'on compresse une image pour en réduire la taille que le transfert réseau se fera plus rapidement. En effet, compresser et décompresser une image consomme du processeur et du temps. Si le temps de compression + le temps de transfert + le temps de décompression est supérieur ou égal au temps de transfert de l'image sans technique de compression, alors le gain est nul, voir négatif.

Aucun commentaire:

Enregistrer un commentaire