lundi 24 septembre 2018

Les images en DICOM - Partie 1

Dans les articles précédents nous avons vu comment DICOM gère, organise et encode les informations médicales. Voyons maintenant comment le standard représente et stocke les images. Il existe, en DICOM, deux grands types de formats pour stocker les images (cf. PS3.5 - section 8.2):
  • Les formats natifs : Ce sont les premiers formats apparus. Ils permettent de stocker les images au format Bitmaps, c'est-à-dire sans compression.  ;
  • Les formats encapsulés: Ces formats permettent de stocker les images en utilisant des techniques de compressions. Ces dernières peuvent être avec ou sans perte de données.
Afin de traiter ces deux approches, plusieurs articles sont nécessaires pour décomposer les idées et ne pas faire un « gros pavé ».

Dans ce billet nous nous intéresserons uniquement à la première approche, c'est-à-dire les formats natifs. Deux autres billets seront consacrés aux formats encapsulés et aux transferts de syntaxes.

1. Les Images


Dans le monde numérique, une image est une matrice rectangulaire de pixels1 (des petits points de différentes couleurs).

Si nous voulions stocker une image, de quelles informations aurions-nous besoin ?
Tout d'abord, Il nous faudrait savoir les dimensions de l'image (sa hauteur et sa largeur).
Ensuite, il faudrait connaitre la valeur des pixels de l'image. Cependant, un pixel peut prendre différentes couleurs (voir la figure ci-dessus). Il faudrait donc pouvoir spécifier la couleur de chaque pixel. Pour cela, il faut pouvoir dire quel « espace de couleur » (représentation des couleurs dans un système de gestion des couleurs en informatique) est utilisé (comme par exemple RGB, HSV ou encore HSL) car oui, il existe différentes manières de coder une couleur.
Il existe ainsi toute une panoplie d'informations nécessaires pour représenter une image.

DICOM a listé tous ces éléments et les a regroupés dans un module « image ». Dans le dictionnaire de données (PS3.6), tous les « Data Element » concernant une image ont l'identifiant de groupe 0028.

2. Encodage d'une image en DICOM


Parmi les tags DICOM les plus utilisés pour caractériser une image, on trouve:

2.1. Rows & Columns


Les tags (0028, 0010) Rows et (0028, 0011) Columns permettent de définir la dimension de l'image. Le tag « Rows » représente la hauteur de l'image et le tag « Columns » spécifie sa largeur.

2.2. Samples Per Pixel


Le tag (0028, 0002) Samples per Pixel spécifie le nombre de canaux de couleur pour un pixel. Par exemple, pour une image en niveaux de gris, un seul canal suffit. Pour une image en couleur utilisant le système de couleur RGB, 3 canaux sont nécessaires (un pour le rouge, un autre pour le vert et un dernier pour le bleu).

2.3. Photometric Interpretation


Le tag (0028,0004) Photometric Interpretation indique l'espace de couleur utilisé. Suivant le type d'image et le format utilisé, cet attribut DICOM peut prendre la valeur :
  • MONOCHROME1 ou MONOCHROME2 pour les images en niveaux de gris.
    • MONOCHROME1 indique que la valeur la moins élevée d'un pixel sera interprétée par du blanc et la valeur la plus élevée par du noir ;
    • MONOCHROME2 indique que la valeur la moins élevée d'un pixel sera interprétée par du noir et la valeur la plus élevée par du blanc.
  • PALETTE COLOR, RGB ou les différentes variantes de YBR pour les images en couleurs (voir PS3.3 section 7.6.3.1.2 pour les valeurs possibles de YBR et leur signification).

2.4. Planar configuration


Le tag (0028,0006) Planar configuration indique l'arrangement des canaux dans la représentation des pixels. Les valeurs possibles de ce champ DICOM sont « 0 » ou « 1 ».
  • La valeur « 0 » signifie que les canaux sont entrelacés pour représenter un pixel. Cette manière de faire est la façon la plus intuitive et celle utilisée par défaut par DICOM. Pour une image RGB, cela signifie que les pixels seront encodés de la manière suivante : R1, G1, B1, R2, G2, B2, ..., etc.
  • La valeur « 1 » indique que chaque canal est encodé de manière continue. On encode déjà tout un canal puis ensuite un autre, et ainsi de suite. Pour une image RGB, cela implique que les pixels seront encodés de la manière suivante R1, R2, R3, ..., G1, G2, G3, ..., B1, B2, B3, etc.
Remarque 1 : Le tag (0028,0006) Planar configuration n'a de sens que si plusieurs canaux interviennent dans la représentation d'un pixel (tag (0028, 0002) Samples Per Pixel supérieur à 1).

Remarque 2 : Le tag (0028,0006) Planar configuration n'a pas non plus de sens si une technique de compression implique une réorganisation des canaux dans le flux compressé. Dans de tels cas, si l'attribut est requis, la valeur à mettre dans ce champ est spécifiée dans la partie PS 3.5 section 8.2 en fonction de la technique de compression utilisée.

2.5. Bits Allocated, Bits Stored & High Bit


Le tag (0028,0100) Bits Allocated spécifie l'espace alloué pour chaque canal d'un pixel exprimé en bit. Les valeurs de ce champ sont en général 8 ou 16 pour une image en niveaux de gris et 24 pour une image couleur.

Le tag (0028,0101) Bits Stored indique le nombre de bits utilisé parmi ceux alloués pour chaque canal. Il est ainsi possible d'allouer 2 octets (Bits Allocated = 16) mais de n'en utiliser que 12. Par exemple, supposons que l'on ait une image en niveaux de gris pour laquelle chaque pixel utilise 8 bits. Chacun de ces pixels peut prendre une valeur entre 0 et 255 (28 valeurs). Le nombre de niveau de gris est donc de 256. Si maintenant on utilise 12 bits au lieu de 8, chaque pixel peut prendre 212 = 4096 valeurs, soit 4096 niveaux de gris. En résumé, les bits stored permettent de représenter la richesse d'une image en terme de nombre de valeurs.

Remarque: Il est possible que tous les bits alloués ne soient pas exploités. Par exemple, si seulement 12 bits sur 16 sont utilisés, les 4 restants seront « masqués » lors de l'interprétation par une application DICOM. Cet espace non utilisé a, dans les débuts du standard, été exploité pour stocker d'autres informations. Cependant, cette technique est aujourd'hui complètement obsolète.

Le tag (0028,0102) High Bit définit où se trouvent les bits utilisés, à l'intérieur de l'espace alloué. Les bits utilisés sont représentés par un segment continu (les bits utilisés sont adjacents). La valeur correspond à l'index du dernier bit utilisé.

Exemple d'utilisation de ces 3 éléments DICOM - Image Monochrome


Supposons que l'on dispose d'une image en niveaux de gris (Monochrome) de 512x512 pixels et que chaque pixel utilise 12 bits.
  • Bits Allocated : Pour stocker 12 bits il nous faut 2 octets (16 bits). (0028,0100) Bits Allocated aura donc pour valeur 16.
  • Bits Stored : Chaque pixel utilise 12 bits. (0028,0101) Bits Stored aura pour valeur 12.
  • High Bit : Sur les 16 bits (numérotés de 0 à 15), seuls 12 sont nécessaires. Nous souhaitons que ce soit les bits 2 à 13. (0028,0102) High Bit aura donc la valeur 13.


Remarque: En pratique, on commence toujours par stocker les bits à partir de l'offset 0. (0028,0102) High Bit est toujours égal à la valeur de Bits Stored - 1.

La taille de l'image stockée est donc 512 x 512 x 2 = 524288 octets = 512 ko.

Exemple d'utilisation de ces 3 éléments DICOM - Image Couleur


Voyons un autre exemple avec une image de couleur de 512 x 512 pixels dans un espace de couleur de type RGB.
  • Photometric Interpretation : Puisque c'est une image couleur RGB, chaque pixel aura 3 canaux. Photometric Interpretation aura pour valeur 3.
  • Bits Allocated : Pour stocker 12 bits il nous faut 2 octets (16 bits). (0028,0100) Bits Allocated aura donc pour valeur 16.
  • Bits Stored : Chaque composante de chaque pixel utilise 12 bits. (0028,0101) Bits Stored aura pour valeur 12.
  • High Bit : Sur les 16 bits (numérotés de 0 à 15), seuls 12 sont nécessaires. Nous souhaitons que ce soit les bits 0 à 11. (0028,0102) High Bit aura donc la valeur 11.


La taille de l'image stockée est donc 512 x 512 x 2 x 3 = 524288 octets = 1.5 Mo.

2.6. Pixel Representation


Le tag (0028, 0103) Pixel Representation indique si les pixels sont encodés avec des octets signés (Pixel Representation a la valeur 1) ou non signés (Pixel Representation a la valeur 0). L'octet non signé est très souvent utilisé par défaut.

Octet « signé » et « non signé » : L'informatique utilise un système binaire à base de « 0 » et « 1 » mais pas de « + » et « - ». Par conséquent, le seul moyen est de convenir que si un nombre est susceptible d'être négatif, on lui réserve un bit pour indiquer le signe. Ce bit de signe est celui le plus à gauche de l'octet.

2.7. Pixel Data


Le tag (7FE0, 0010) Pixel Data permet de stocker les pixels. L'ordre des pixels encodés est de gauche à droite et de haut en bas. Le coin supérieur gauche (de coordonnées 1,1) est encodé en premier, suivi du reste de la première ligne. Vient ensuite le premier pixel de la seconde ligne (de coordonnées 2,1), puis le reste de la seconde ligne, et ainsi de suite.

Exemple d'encodage d'une image en niveau de gris:

Remarque: L'élément (7FE0, 0010) Pixel Data ne fait étonnement pas partie du groupe 0028 (le groupe « Image »). Le standard ne spécifie pas les raisons, mais en analysant la partie PS3.6 - section 6 du standard, on peut remarquer deux choses:
  • Le groupe 7FE0 ne dispose que de trois élements : (7FE0, 0008) Float Pixel Data, (7FE0, 0009) Double Float Pixel Data et (7FE0, 0010) Pixel Data. ;
  • Le groupe 7FE0 se trouve à la fin du dictionnaire des éléments DICOM.
On peut en déduire que l'identifiant 7FE0 représente le groupe « Pixel » et que DICOM a voulu séparer le stockage des pixels du reste des caractéristiques d'une image.
Pourquoi cette séparation ?
On peut supposer que les concepteurs du standard préféraient stocker les pixels en fin de fichier DICOM, afin de pouvoir extraire facilement les méta données DICOM sans les pixels.

Remarque: La VR de Pixel Data peut être OB ou OW suivant le nombre d'octets nécessaire pour stocker un pixel. Pour rappel, si la VR est OW, il faut effectuer un byte swapping pour interpréter les octets.

Remarque: La VR de Pixel Data doit être OW si l'encodage est en Implicit VR Little Endian.

3. Exemple d'encodage d'une image en DICOM


Supposons que l'on veuille encoder l'image suivante :

Cette image a une dimension de 6 x 6 pixels et utilise un espace de couleur RGB. Pour encoder cette image, nous allons utiliser les valeurs par défaut pour les tags Planar Configuration et Pixel Representation. Puisque l'on veut encoder une image en couleur, 3 canaux sont nécessaires pour chaque pixel. On utilisera un octet par canal (un par composante). Cela représente une taille de 3 x 36 = 108 octets pour encoder les 36 pixels de l'image.

L'encodage DICOM donne le résultat suivant:
(0028,0002) US #2 [3] SamplesPerPixel
(0028,0004) CS #4 [RGB] PhotometricInterpretation
(0028,0006) US #2 [0] PlanarConfiguration
(0028,0010) US #2 [6] Rows
(0028,0011) US #2 [6] Columns
(0028,0100) US #2 [8] BitsAllocated
(0028,0101) US #2 [8] BitsStored
(0028,0102) US #2 [7] HighBit
(0028,0103) US #2 [0] PixelRepresentation
(7FE0,0010) OW #108 [CC CC CC FF EE A9 FF EE A9 FF EE A9 FF EE A9 CC CC CC
                     FF EE A9 FF EE A9 FF EE A9 FF EE A9 FF EE A9 FF EE A9
                     FF EE A9 00 00 00 FF EE A9 FF EE A9 00 00 00 FF EE A9
                     FF EE A9 FF EE A9 FF EE A9 FF EE A9 FF EE A9 FF EE A9
                     FF EE A9 FF EE A9 00 00 00 00 00 00 FF EE A9 FF EE A9
                     CC CC CC FF EE A9 FF EE A9 FF EE A9 FF EE A9 CC CC CC] PixelData


4. Les Multi-frames


Il est possible de stocker plus d'une image dans un objet DICOM. On appelle cela des Multi-frames. Le nombre d'images contenu dans un objet DICOM est indiqué par le tag (0028,0008) Number of Frames. Cet élément contient un entier positif indiquant combien d'images sont présentes dans le tag (7FE0, 0010) Pixel Data.
L'élément (7FE0, 0010) Pixel Data contient les différentes images enchaînées les unes dernières les autres.
Pour rendre un peu plus concrètes les explications, reprenons l'exemple ci-dessus (smiley de dimension 6 x 6). Si nous voulions créer un objet avec deux images de smiley, l'objet DICOM ressemblerait à :

(0028,0002) US #2 [3] SamplesPerPixel
(0028,0004) CS #4 [RGB] PhotometricInterpretation
(0028,0006) US #2 [0] PlanarConfiguration
(0028,0008) IS #2 [2] NumberOfFrames
(0028,0010) US #2 [6] Rows
(0028,0011) US #2 [6] Columns
(0028,0100) US #2 [8] BitsAllocated
(0028,0101) US #2 [8] BitsStored
(0028,0102) US #2 [7] HighBit
(0028,0103) US #2 [0] PixelRepresentation
(7FE0,0010) OW #216 [...] PixelData

On remarque que par rapport à l'objet DICOM précédent, un nouveau tag a fait son apparition et un autre a été modifié. Le tag Pixel Data contient maintenant 216 octets (au lieu de 108). La délimitation entre les images se fait par calcul grâce aux différents tags DICOM indiquant les caractéristiques d'une image.
Une image a une taille de Rows x Colums x SamplesPerPixel x (BitsAllocated / 8) octets. Dans notre cas, chaque image occupe 6 x 6 x 3 x (8 / 8) = 108 octets. Pour aller d'une image à l'autre il faut donc sauter de 108 octets.

5. Les palettes de couleurs


Dans les exemples précédents, nous avons encodé une petite image de 6 x 6 pixels. Supposons maintenant que nous ayons une image couleur de 512 x 512 pixels, qui dispose de 256 couleurs différentes. Utiliser 1 octet par composante RGB est suffisant pour encoder ces 256 couleurs. La taille sera donc de 512 x 512 x 3 = 768 ko.

Les images basées sur un encodage RGB peuvent rapidement occuper un espace de stockage considérable. La question que l'on peut se poser est : N'y aurait-il pas un moyen de réduire cet espace occupé ? Une réponse possible est l'utilisation d'une palette de couleurs.

Les annexes PS3.3 - C.7.6.3.1.5, PS3.3 - C.7.6.3.1.6 et PS3.5 - A.4 décrivent l'utilisation des palettes de couleurs pour encoder une image en couleur.
L'idée est d'utiliser une table de correspondance (appelée « Lookup Table »). À chaque valeur de cette table est associée une clé (appelée « index »). On accède à chaque valeur de la table par sa clé. Côté pixels, on ne stocke plus la couleur (les 3 composantes RGB par exemple) mais la clé permettant d'accéder à la couleur dans la table de correspondance.
Le pixel i fait référence à l'index 23 de la palette de couleur. Il est de couleur verte.
Un tel système d'encodage permet de gagner de la place pour stocker une image.

Reprenons l'exemple ci-dessus de l'image couleur de 512 x 512 pixels avec 256 couleurs. Avec un encodage RGB, l'espace occupé par les pixels est de 768 ko.
En utilisant un encodage par palette de couleur, l'espace occupé serait de
  • pour l'image : 512 x 512 x 1 =  262 144 octets = 256 ko
  • pour la palette de couleur: 256 * 3 = 768 octets
La taille totale de l'image serait donc 262 912 octets ≃ 256 ko, soit 1/3 de la taille avec un encodage RGB.

5.1 Encodage DICOM


DICOM utilise 3 types de Data Element pour décrire l'encodage des palettes de couleurs :
  • (0028, 1101-1103) Palette Color Lookup Table Descriptor: Pour la description des données dans les éléments Palette Color Lookup Table Data ;
  • (0028, 1201-1203) Palette Color Lookup Table Data: Pour stocker les données de la palette de couleurs ;
  • (7FE0, 0010) Pixel Data: Pour stocker l'index de la table de correspondance de chaque couleur de pixel.

5.1.1. Palette Color Lookup Table Descriptor


Ce type de Data Element permet de décrire le format des données de la palette. Les palettes de couleurs utilisent le modèle RGB, il faut donc 1 Data Element pour décrire chacune des 3 couleurs primaires.
  • (0028, 1101) Red Palette Color Lookup Table Descriptor pour la composante rouge ;
  • (0028, 1102) Green Palette Color Lookup Table Descriptor pour la composante verte ;
  • (0028, 1103) Blue Palette Color Lookup Table Descriptor pour la composante bleue.
Chacun de ces éléments est composé de 3 valeurs:
  • La première valeur « Number of entries » permet de spécifier le nombre d'entrées dans la table de correspondance (Lookup Table). Il est possible d'aller jusqu'à 216 entrées. De manière générale, on trouve souvent 256 comme nombre d'entrées (et donc de couleurs).
  • La seconde valeur « First value mapped » indique la première entrée (le premier index) de la table de correspondance. En général, c'est toujours la valeur 0. Si d'aventure un pixel fait référence à un index inférieur à « First value mapped », alors c'est la « First value mapped » qui sera utilisée. De manière similaire, si un pixel fait référence à un index supérieur à la taille du tableau (Number of entries), alors c'est la dernière entrée de la table qui sera utilisée.
  • La dernière valeur « Number of bits » caractérise le nombre de bits utilisés pour chaque  donnée dans Lookup Table Data. Elle peut prendre les valeurs 8 ou 16. 

Remarque: Le tag (0028, 1104) Alpha Palette Color Lookup Table Descriptor existe dans le dictionnaire de données (PS3.6) et dans la description de la section PS3.3 - C.7.6.3.1.5 du standard. Mais une note de la section PS3.3 - C.7.6.3.1.1 explique que l'utilisation du canal Alpha a été retirée du standard (valeur « 4 » interdite dans le tag (0028, 0002) Samples Per Pixel, et valeur « ARGB » interdite dans (0028, 0004) Photometric Interpretation). Le tag concernant le canal Alpha est conservé uniquement à des fins de compatibilité.

5.1.2. Palette Color Lookup Table Data


Ce type de Data Element permet de stocker les données de la palette. Les palettes de couleurs utilisant le modèle RGB, il faut donc 1 Data Element pour chacune des 3 couleurs primaires.
  • (0028, 1201) Red Palette Color Lookup Table Data : Pour stocker les n composantes de rouge des n entrées possibles de la table de correspondance ;
  • (0028, 1202) Green Palette Color Lookup Table Data : Pour stocker les n composantes de vert des n entrées possibles de la table de correspondance ;
  • (0028, 1203) Blue Palette Color Lookup Table Data : Pour stocker les n composantes de bleu des n entrées possibles de la table de correspondance.
Il y a autant de valeurs dans chacun de ces éléments que de valeurs spécifiées par « Number of entries » dans les descriptions des Lookup Table.

Remarque : Les Data Element (0028, 1201-1204) Palette Color Lookup Table Data ont une VR SS ou US. Ces deux VR  utilisent donc 2 octets pour représenter une valeur. Dans le cas ou la valeur « Number of bits » des Data Element (0028, 1101-1104) Palette Color Lookup Table Descriptor est 8 bits (1 octet), il est possible de représenter deux entrées du tableau avec une seule valeur US ou SS.

5.1.3 Pixel Data


Dans le cas d'utilisation d'une palette de couleurs, le tag (7FE0, 0010) Pixel Data stocke l'index d'accès à une couleur dans la table de correspondance (contrairement à l'encodage monochrome ou RGB qui stocke les valeurs de chaque pixel). 

5.1.4 Exemple concret


Reprenons l'image du smiley de 6 x 6 pixels et encodons la avec une palette de couleur
La section PS3.3 - C.7.6.3.1.2 indique que si la valeur PALETTE COLOR est utilisée, alors (0028, 0002) Sample Per Pixels doit avoir la valeur « 1 ». L'encodage DICOM donne le résultat suivant:
(0028,0002) US #2 [1] SamplesPerPixel
(0028,0004) CS #4 [PALETTE COLOR] PhotometricInterpretation
(0028,0006) US #2 [0] PlanarConfiguration
(0028,0010) US #2 [6] Rows
(0028,0011) US #2 [6] Columns
(0028,0100) US #2 [8] BitsAllocated
(0028,0101) US #2 [8] BitsStored
(0028,0102) US #2 [7] HighBit
(0028,0103) US #2 [0] PixelRepresentation
(0028,1101) US #6 [4\0\8] RedPaletteColorLookupTableDescriptor
(0028,1102) US #6 [4\0\8] GreenPaletteColorLookupTableDescriptor
(0028,1103) US #6 [4\0\8] BluePaletteColorLookupTableDescriptor
(0028,1201) US #4 [255 127 0 0] RedPaletteColorLookupTableData
(0028,1201) US #4 [242 127 0 0] GreenPaletteColorLookupTableData
(0028,1201) US #4 [0 127 0 0] BluePaletteColorLookupTableData
(7FE0,0010) OW #36 [01 00 00 00 00 01 00 00 00 00 00 00 00 02 00 00 02 00
                    00 00 00 00 00 00 00 00 02 02 00 00 01 00 00 00 00 01] PixelData


Remarque: L'utilitaire dcmquant du toolkit dcmtk a été utilisé pour générer l'exemple ci-dessus à partir de l'image du smiley encodé en RGB.

Remarque: DICOM impose d'avoir un nombre pair pour la taille de chaque DICOM Element. C'est pourquoi l'outil dcmquant duplique la dernière valeur. Cela ne change rien à l'interprétation des palettes de couleurs car tout index supérieur à la taille du tableau sera interprété comme le dernier index de la table de correspondance.

(1) Pixel : Provient de la locution anglaise picture element, qui signifie « élément d'image ».

lundi 10 septembre 2018

L'encodage d'objet DICOM - Format JSON

La partie PS3.18 (Annexe F) du standard définit un encodage des objets DICOM au format JSON. Ce modèle de représentation est appelé « DICOM JSON Model ».
Tout comme le format XML, JSON est 100% textuel, indépendant d'un langage (on respecte la notion d'universalité - cf. Introduction) et utilisé pour transférer des structures de données légères.

« DICOM JSON Model » complémente le format XML « Native DICOM Model ». Tout comme le format XML, le format JSON pourrait être utilisé pour échanger des objets DICOM, mais le standard recommande de ne l'employer que dans des cas bien précis, tels que des applications mobiles qui utiliseraient les services Web DICOM (QIDO-RS par exemple).

Ces applications n'ont pas besoin de savoir lire des objets DICOM standard, et donc d'embarquer des bibliothèques particulières permettant de décoder du DICOM.

Remarque : Que ce soit l'encodage XML ou JSON, ces deux alternatives sont très proches l'une de l'autre car elles permettent d'avoir une représentation 100% textuelle de l'objet DICOM et de ne se reposer que sur des outils standards de traitement XML ou JSON. Le choix entre JSON et XML est donc assez subjectif.
Actuellement, le standard recommande le format XML pour des traitements sur un serveur (validation ou coercition d'attributs par exemple) et le format JSON pour les transferts réseaux sur les applications mobiles en DICOM web (métadonnées dicom). JSON étant moins verbeux que XML, ce choix de format pourrait être amené à disparaître avec le développement des outils JSON qui permettraient d'être iso-fonctionnel par rapport aux outils XML.

Il est vivement conseillé d'avoir lu les parties Encodage Classique - partie 1 et Encodage Classique - partie 2 pour comprendre ce billet.

1. Présentation de JSON


Le format JSON utilise une syntaxe très simple mais qui permet de représenter n'importe quelle donnée. Cette syntaxe est composée de 4 types primitifs et 2 types structurés.

1.1 Les types primitifs

  • Strings :  une séquence de 0 ou n caractères Unicode. Elles sont obligatoirement entourées de guillemets (non interchangeables avec des apostrophes) ;
  • Numbers : un nombre décimal signé qui peut contenir une part fractionnable ou élevée à la puissance. JSON ne permet pas les nombres inexistants (NaN), et ne fait aucune différence entre un entier et un flottant ;
  • booleans: Permet de représenter un booléen. Deux valeurs sont autorisées « true » ou « false » ;
  • null: indique une valeur vide, utilisant le mot clé « null ».

1.2 Les types structurés

  • Les Objets : Un objet (object) est un ensemble de paires « clé:valeur ».  La « clé » est de type « string », suivie du caractère « : » puis de la « valeur ». Chaque paire composant l'objet est séparée de la précédente par le caractère « , ». Un objet commence par le caractère « { » et termine par le caractère « } » ;

  • Les tableaux : Un tableau (array) est une collection de plusieurs valeurs. Il commence par le caractère « [ » et termine par le caractère « ] ». Chaque valeur est séparée de la précédente par le caractère « , ».
Dans une paire « clé:valeur », la valeur peut être d'un des 6 types présentés ci-dessus.


Exemple d'objet JSON simple:
{
 "nom":"Dupond",
 "prenoms":["Jean", "Paul", "Jacques"],
 "age":37,
 "representantLegal":null,
 "fumeur":true
}

Exemple d'objet JSON complexe (structures JSON imbriquées)
{
 "nom":"Dupond",
 "prenoms":["Marie"],
 "age":12,
 "representantLegal":{
   "nom":"Dupond",
   "prenoms":["Jean", "Paul", "Jacques"],
   "age":37,
   "representantLegal":null,
   "fumeur":true
 },
 "fumeur":false
}

2. Encodage DICOM


En DICOM, la brique de base d'un objet est le Data Element. Cet élément est représenté en JSON par la syntaxe suivante :

"ggggeeee": {
  "vr": ... ,
  "Value" | "InlineBinary" | "BulkDataURI": ...
}

Un Data Element est représenté par une paire « clé:valeur » dont la « clé » est formée des 8 caractères en capital de l'identifiant hexadécimal du tag DICOM (ggggeeee, ou gggg est le groupe et eeee l'élément dans le groupe). La valeur est un objet JSON composé de deux sous paires. La première (« vr ») permet de représenter le type du Data Element. La seconde paire (que l'on appellera « content ») indique la valeur du Data Element. En fonction de la VR, la « clé » de content peut prendre une des valeurs suivantes: Value, InlineBinary ou BulkDataURI.

Le tableau suivant résume le mapping entre chaque VR DICOM, le type JSON associé, et la clé de la représentation JSON de la valeur d'un Data Element. Le mapping entre les VR DICOM et les types JSON est disponible dans la partie PS3.18 - Annexe F2.3.


VR Clé de content Type JSON de content
AE
Value
String
AS
Value
String
AT
Value
String
CS
Value
String
DA
Value
String
DS
Value
Number
DT
Value
String
FL
Value
Number
FD
Value
Number
IS
Value
Number
LO
Value
String
LT
Value
String
OB
InlineBinary ou BulkDataURI
si InlineBinary : Flux d'octet encodé en Base64
si BulkDataURI: String
OD
InlineBinary ou BulkDataURI
si InlineBinary : Flux d'octet encodé en Base64
si BulkDataURI: String
OF
InlineBinary ou BulkDataURI
si InlineBinary : Flux d'octet encodé en Base64
si BulkDataURI: String
OL
InlineBinary ou BulkDataURI
si InlineBinary : Flux d'octet encodé en Base64
si BulkDataURI: String
OW
InlineBinary ou BulkDataURI
si InlineBinary : Flux d'octet encodé en Base64
si BulkDataURI: String
PN
Value
Tableau de systèmes d'écritures
SH
Value
String
SL
Value
Number
SQ
Value
Tableau de DICOM JSON Objects
SS
Value
Number
ST
Value
String
TM
Value
String
UC
Value
String
UI
Value
String
UL
Value
Number
UN
InlineBinary ou BulkDataURI
Flux d'octet encodé en Base64
UR
Value
String
US
Value
Number
UT
Value
String

Remarque: Au format JSON, un objet DICOM est appelé « DICOM JSON Object ».

2.1. L'élément « Value »


2.1.1. Cas général


Pour les Data Element ayant une VR autre que PN, SQ, OB, OD, OF, OL, OW ou UN, l'élément « Value » contient un tableau de valeurs. En effet, un Data Element pouvant avoir plusieurs valeurs, cette caractéristique est représentée en JSON par un tableau.

Exemple 1 - Tableau d'un élément:
"00100020": {
 "vr": "LO",
 "value": ["12345"]
}

Exemple 2 - Tableau de plusieurs éléments:
"00080061": {
  "vr": "CS",
  "value": ["CT", "PET"]
}

2.1.2. Cas du type PN


Pour les Data Element avec une VR PN, « Value » contient un tableau d'objets JSON. Chaque objet de ce tableau peut contenir trois éléments : Alphabetic, Ideographic et Phonetic.
Chacun de ces 3 éléments a pour valeur une chaîne de caractères qui respecte le formalisme suivant :

FamilyName^GivenName^MiddleName^NamePrefix^NameSuffix.

Tout comme pour les autres systèmes d'encodages DICOM (classique ou XML), chacun des composants  FamilyName, GivenName, MiddleName, NamePrefix et NameSuffix est optionnel.

Exemple:
"00100010": {
  "vr":"PN",
   "value":[{
      "Alphabetic":"Yamada^Tarou",
      "Ideographic":"山田^太郎",
      "Phonetic":"やまだ^たろう"
   }]
}

2.1.3. Cas du type SQ


Pour les Data Element avec une VR SQ, « Value » contient un tableau d'objets JSON. Chacun de ces objets représente un Item de la séquence. Chaque Item étant à son tour un « JSON DICOM Object ».

Exemple:
"00081110":{
 "vr":"SQ",
 "value":[{
    "00081150":{
    "vr":"UI",
    "value":["1.2.840.10008.3.1.2.3.1"]
   },
   "00081155":{
    "vr":"UI",
    "value":["1.2.3.4.5.6"]
   }
  }]
}

2.2. L'élément « InlineBinary »


Cet élément permet d'encoder en base64 la valeur des Data Element dont la VR est OB, OD, OF, OW, ou UN. En effet, les VR précédemment citées contiennent des données binaires. Or JSON étant un langage textuel, il est nécessaire de convertir les données binaires au format texte. DICOM a choisi d'utiliser l'encodage base64 pour effectuer cette transformation.

Exemple:
"7FE00010":{
  "vr":"OW",
  "InlineBinary":"Qm9uam91ciDDoCB0b2k="
}

Remarque : Tout comme en XML, l'encodage de données binaires en base64 alourdit la taille de l'objet JSON. L'encodage JSON n'est donc pas optimal pour le transfert d'objet DICOM.

2.3. L'élément « BulkDataURI »


Cet élément permet d'encoder une référence à un blob (Binary Large OBject). Le but étant d'éviter de stocker de larges données DICOM dans une structure JSON. Ce blob peut être situé localement sur un système de fichiers ou encore sur un réseau.

Exemple 1 - blob situé localement sur un système de fichiers:
"7FE00010":{
  "vr":"OW",
  "BulkDataURI":"file:/C:/monRep/file.dcm?offset=16&length=524"
}

Exemple 2 - blob situé sur un réseau:
"7FE00010":{
  "vr":"OW",
  "BulkDataURI":"http://server/rs/studies/1.2.3/series/5.6.7"
}


3. Exemple d'un objet DICOM encodé en JSON


Un exemple est disponible dans le standard dans l'annexe PS3.18 Annexe F.4.

Un exemple de fichier DICOM complet au format JSON est également disponible ici.