Uploading dicom segmentation instance

Im trying to upload a test segmentation instance to orthanc and am getting the error:
{
“HttpError” : “Not Found”,
“HttpStatus” : 404,
“Message” : “Inexistent tag”,
“Method” : “POST”,
“OrthancError” : “Inexistent tag”,
“OrthancStatus” : 21,
“Uri” : “/instances/”
}
This is my code:

ref_instance_id = study.get_image_path()
img_arr = study.load_image(ref_instance_id)

# Create a 3D uint8 image filled with zeros with the same shape as img_arr
zeros_img = np.zeros(img_arr.shape, dtype=np.uint8)
# Set a cube with len 10 at the center of the image as 1
x_middle = img_arr.shape[1] // 2
y_middle = img_arr.shape[2] // 2
z_middle = img_arr.shape[0] // 2
len_cube = 10
zeros_img[x_middle-len_cube:x_middle+len_cube, y_middle-len_cube:y_middle+len_cube, z_middle-len_cube:z_middle+len_cube] = 1
len_cube = 3
zeros_img[x_middle-len_cube:x_middle, y_middle-len_cube:y_middle, z_middle-len_cube:z_middle] = 2
zeros_img[x_middle+1:x_middle+len_cube, y_middle+1:y_middle+len_cube, z_middle+1:z_middle+len_cube] = 3

# study.save_segmentation("input", zeros_img)
segmentation_array = zeros_img
print("Creating a new segmentation instance")
original_dcm = study._load_dcm_object(ref_instance_id)
assert (
    original_dcm.pixel_array.shape == segmentation_array.shape
), f"Segmentation array shape {segmentation_array.shape} does not match the original DICOM image shape {original_dcm.pixel_array.shape}."

# Create a new DICOM dataset
# Set the transfer syntax to Explicit VR Little Endian
file_meta = Dataset()
file_meta.MediaStorageSOPClassUID = SegmentationStorage
file_meta.MediaStorageSOPInstanceUID = generate_uid()
file_meta.TransferSyntaxUID = ExplicitVRLittleEndian

# Create the FileDataset
ds = FileDataset(
    "segmentation.dcm", {}, file_meta=file_meta, preamble=b"\0" * 128
)

# Add patient and study information
ds.PatientName = original_dcm.PatientName
ds.PatientID = original_dcm.PatientID
ds.StudyInstanceUID = original_dcm.StudyInstanceUID
# Check if series with SEG modality exists in same study as ref_img_type
ref_instance =  study.orthanc.instances.get(ref_instance_id)
ref_study = ref_instance.series.study
seg_series_uid = None
series_list = ref_study.series
for serie in series_list:
    if serie.main_dicom_tags.get("Modality") == "SEG":
        seg_series_uid = serie.tags["SeriesInstanceUID"]
        break
if seg_series_uid is None:
    print("Creating a new series for the segmentations")
    seg_series_uid = generate_uid()
else:
    print(
        f"Found existing series with SeriesInstanceUID {seg_series_uid}"
    )
ds.SeriesInstanceUID = seg_series_uid

ds.SOPInstanceUID = file_meta.MediaStorageSOPInstanceUID
ds.Modality = "SEG"
ds.StudyID = original_dcm.StudyID
ds.InstanceNumber = original_dcm.InstanceNumber

# Add other required attributes
ds.SpecificCharacterSet = "ISO_IR 100"
ds.ImageType = ["DERIVED", "PRIMARY"]
ds.ContentDate = datetime.now().strftime("%Y%m%d")
ds.ContentTime = datetime.now().strftime("%H%M%S")

# Define the segments
labels = {
    item[1]["segment_number"]: item[0]
    for item in  config["labels"].items()
}

ds.SegmentSequence = []

for label, name in labels.items():
    segment = Dataset()
    segment.SegmentNumber = label
    segment.SegmentLabel = name
    segment.SegmentAlgorithmType = (
        "MANUAL" if True else "AUTOMATIC"
    )
    segment.SegmentAlgorithmName = "FollicleFinder"
    ds.SegmentSequence.append(segment)

# Create Referenced Series Sequence
ref_series_seq = Dataset()
ref_series_seq.SeriesInstanceUID = original_dcm.SeriesInstanceUID
ref_series_seq.ReferencedInstanceSequence = []

# Reference the original 3D instance
ref_instance = Dataset()
ref_instance.ReferencedSOPClassUID = original_dcm.SOPClassUID
ref_instance.ReferencedSOPInstanceUID = original_dcm.SOPInstanceUID
ref_series_seq.ReferencedInstanceSequence.append(ref_instance)

# Add the Referenced Series Sequence to the dataset
ds.ReferencedSeriesSequence = [ref_series_seq]

# Convert the numpy array to a SimpleITK image
seg_image = sitk.GetImageFromArray(segmentation_array.astype(np.uint16))

# Set the origin and spacing to match the original DICOM
seg_image.SetSpacing(
    list(original_dcm.PixelSpacing) + [original_dcm.SpacingBetweenSlices]
)

# Add the necessary DICOM tags for segmentation
ds.BitsAllocated = 8
ds.BitsStored = 8
ds.HighBit = 7
ds.SamplesPerPixel = 1
ds.PhotometricInterpretation = "MONOCHROME2"
ds.NumberOfFrames = segmentation_array.shape[0]
ds.Rows = segmentation_array.shape[1]
ds.Columns = segmentation_array.shape[2]
ds.PixelRepresentation = 0

# save numpy array to pixel array
ds.PixelData = segmentation_array.astype(np.uint8).tobytes()

# Update the PixelData VR to 'OB' for 8-bit data
ds[0x7FE0, 0x0010].VR = 'OB'
import io
import requests
# Upload the segmentation to the Orthanc server
print("Uploading segmentation to Orthanc server")
dcm_bytes = io.BytesIO()
ds.save_as(dcm_bytes)
response = requests.post(
    f'http://localhost:8042/instances/',
    data=dcm_bytes.getvalue(),
    auth=(
        "",
        "",
    ),
)
print(response.text)
response.raise_for_status() # Error occurs here
new_segmentation_id = response.json().get("ID")

# Download the segmentation from the Orthanc server
print("Downloading segmentation from Orthanc server")
downloaded_dcm = study._load_dcm_object(new_segmentation_id)
seg_arr = downloaded_dcm.pixel_array

I checked that the 4 main dicom tags (Orthanc identifiers — Orthanc Book documentation) are present.

Hello

I would retry this with --verbose or even --trace.

As you know, there are several DICOM type 1 tags that are mandatory. Mere uids are not enough.

You might want to save your instance and run dciodvfy on it (See Dicom3tools Software (dclunie.com) – install with sudo apt install dcm3tools or the equivalent for your platform)

(see also dicom-validator)

HTH

Hi Benjamin,
Thank you for your help. Indeed I was missing several tags that I was able to solve with the dicom-validator.
Thank you very much!!
Best regards,
Leopold

1 Like