Behaviour notes¶
pydcm aims for value-for-value correctness with the conventions Python DICOM users already expect — for anything not listed here, standard DICOM behaviour applies. The points below are pydcm's deliberate choices and current limits.
Deliberate behaviours¶
-
PALETTE COLOR
pixel_arrayauto-expands to RGB. pydcm applies the palette LUT and returns an[H, W, 3]RGB array — usually what you want. For the raw index image, usepydcm.pixels.apply_color_lutto control the index → RGB step yourself. -
save_asof a Big-Endian / Deflated image raises rather than silently rewriting it. Deep Big-Endian support in the native parser was judged too risky for a retired transfer syntax — pydcm refuses rather than produce a file with dropped pixels. -
Big-Endian
pixel_arraybyteorder is normalized to native. The values are unchanged; only the array's reported byteorder differs (int16rather than>i2). -
generate_uid()mints under pydcm's own registered root —1.2.826.0.1.3680043.9.7155.(PYDCM_ROOT_UID), so the UIDs pydcm creates carry its own identity. UIDs are opaque unique strings, so this is transparent in practice; pass an explicitprefix=for a different root, orprefix=Nonefor a2.25.UUID-derived UID.
Extra detail you may notice¶
pydcm is a superset, so you may see more than the minimum:
- Private-tag names resolve from a 12,608-pattern vendor dictionary, so tags
that are often printed as
Unknowncome back named (e.g.DLP,Total Saving Dose). - One private sequence that is usually left opaque, pydcm parses.
- The keyword ↔ tag ↔ VR dictionary holds 17,699 entries — a strict superset of the standard dictionaries — so attribute names resolve broadly.
- pydcm encodes too:
Dataset.compress(ts)transcodes to RLE / JPEG-2000-lossless / JPEG-LS / HTJ2K / JPEG-XL, bit-lossless and genuinely encapsulated — no plugin stack required.
RT: two things worth knowing¶
-
DVH.countsandDVH.cumulativeare both arrays, always. pydcm computes the differential histogram and its suffix-sum together and hands you both, so neither attribute is a DVH object you have to convert.bins/bincentersare the dose axis in Gy. -
A constraint with no answer is
nan, not0 Gy.dvh.D2ccon a 0.5 cm³ structure asks about volume that is not there. NaN says so; zero would be a dose, and a wrong one. The CLI writes the same reading as JSONnull.
Known limits¶
file_metasurfaces the three mandatory group-0002 UIDs (Media Storage SOP Class / Instance, Transfer Syntax), not the optional group-0002 elements.- A from-scratch
save_as(no source file) writes Implicit or Explicit VR Little Endian — it honoursfile_meta.TransferSyntaxUID/implicit_vr=and includes uncompressed PixelData — but does not produce a compressed/ encapsulated or Big-Endian file from scratch (useDataset.compress(ts)for compression).
Reporting unexpected behaviour¶
If you hit a behaviour that isn't listed here and looks wrong, it probably is — the policy is value-for-value correctness except where this page says otherwise.