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 :
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 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:
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 :
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 ».
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 » 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:
En appliquant le même algorithme de compression sans perte que ci-dessus (remplacer « 1000 » par « a »), on obtient la suite :
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.
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.
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).
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:
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).
Des exemples sont disponibles dans la section 3.2.3. ci-dessous.
L'encodage de chaque item se fait en « Explicit Length » et de la manière suivante:
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
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
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.
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).
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).
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
- Image Monochrome Encapsulé sans Basic Offset Table
- Image Monochrome Encapsulé Fragmenté sans Basic Offset Table
- Image RGB Encapsulé avec Basic Offset Table
- Image Monochrome Multi-Frame Encapsulé sans Basic Offset Table
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