Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pixel Data with undefined length must start with an item tag #738

Closed
vsoch opened this issue Sep 13, 2018 · 9 comments
Closed

Pixel Data with undefined length must start with an item tag #738

vsoch opened this issue Sep 13, 2018 · 9 comments
Labels

Comments

@vsoch
Copy link
Member

vsoch commented Sep 13, 2018

Opening an issue proper here - I commented on an old PR and that's probably not desired :)


hey @pydicom/pydcom-fff ! We are hitting this issue in deid after cleaning data (replacing some values with 0) and trying to save the image. Complete traceback is here: pydicom/deid#65 (comment) and I'll also copy paste the basic operations for quick viewing here:

  1. we read in the dicom
  2. we identify a coordinate to black out, e.g.,
 coordinates
[[0, 0, 800, 59]]

Then we fill in with black (0), this is a copy of the array called "cleaned" We replace the PixelData with cleaned (and this may be where the issue arises, in how I am saving here)?

dicom.PixelData = cleaned.tostring()

and then the standard save for the dicom triggers the error seen here:

dicom.save_as(dicom_name)
Traceback (most recent call last):
  File "/home/vanessa/anaconda3/lib/python3.6/site-packages/pydicom-1.1.0-py3.6.egg/pydicom/tag.py", line 30, in tag_in_exception
    yield
  File "/home/vanessa/anaconda3/lib/python3.6/site-packages/pydicom-1.1.0-py3.6.egg/pydicom/filewriter.py", line 475, in write_dataset
    write_data_element(fp, dataset.get_item(tag), dataset_encoding)
  File "/home/vanessa/anaconda3/lib/python3.6/site-packages/pydicom-1.1.0-py3.6.egg/pydicom/filewriter.py", line 435, in write_data_element
    raise ValueError('Pixel Data with undefined length must '
ValueError: Pixel Data with undefined length must start with an item tag

Is the error one level up where we replace the data, and if not, how do we deal with this particular circumstances? I am attaching the image in question to debug, and @fimafurman and I can add further detail if information is needed. Thanks for the help!
IMG00001.dcm.tar.gz

@scaramallion
Copy link
Member

The dataset is a compressed transfer syntax (1.2.840.10008.1.2.4.70, JPEGLossless). Compressed transfer syntaxes have 'undefined length' (i.e. 0xFFFFFFFF) and are encapsulated as per Part 5, Annex A. Uncompressed transfer syntaxes (implicit/explicit little/big) don't require encapsulation.

Assuming you're going from compressed ds.PixelData -> uncompressed ds.pixel_array -> uncompressed ds.PixelData then you'll probably first have to change the transfer syntax to an appropriate (uncompressed) value before trying to save since the file writer assumes that with a compressed transfer syntax the pixel data has been encapsulated (and hence tries to find the item tag).

If you're maintaining the compression then you first have to encapsulate your data (there are encapsulation functions in the encaps module that will be present in the v1.2 release and are in the current master), then use the resulting output to set ds.PixelData.

@scaramallion
Copy link
Member

scaramallion commented Sep 13, 2018

Would this be a better message?

ValueError: Pixel Data encoded using a compressed transfer syntax must be encapsulated however no item tag was found. Please check the transfer syntax is appropriate and that your pixel data has been encapsulated

@vsoch
Copy link
Member Author

vsoch commented Sep 14, 2018

A change is a good idea! I would be more direct - if it's hit for this save, then maybe the user should hear "if saving originally compressed as uncompressed data be sure to change the ds.TransferSyntax (or whatever is the appropriate field).

For this instance, what specific commands / steps do you recommend? It sounds like the upcoming v1.2 release will have functions that could be useful, but we should have a workaround for now.

@vsoch
Copy link
Member Author

vsoch commented Sep 14, 2018

hey @scaramallion could you give an example of how to use the functions here?

https://github.com/pydicom/pydicom/blob/master/pydicom/encaps.py

I tried (cleaned is a uint8 numpy array)

In [42]: encapsulate(cleaned)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-42-8a1999fc0d60> in <module>()
----> 1 encapsulate(cleaned)

<ipython-input-40-24e31b7fee0d> in encapsulate(frames, fragments_per_frame, has_bot)
    567         # `itemised_length` is the total length of each itemised frame
    568         itemised_length = 0
--> 569         for item in itemise_frame(frame, fragments_per_frame):
    570             itemised_length += len(item)
    571             output.extend(item)

<ipython-input-40-24e31b7fee0d> in itemise_frame(frame, nr_fragments)
    501     """
    502     for fragment in fragment_frame(frame, nr_fragments):
--> 503         yield itemise_fragment(fragment)
    504 
    505 

<ipython-input-40-24e31b7fee0d> in itemise_fragment(fragment)
    466     item += pack('<I', len(fragment))
    467     # fragment data
--> 468     item += fragment
    469 
    470     return item

TypeError: ufunc 'add' did not contain a loop with signature matching types dtype('S8') dtype('S8') dtype('S8')

And if a function in here works, am I allowed to include the file (unchanged with pydicom LICENSE) in deid until the official 1.2 release (that I can require for install?)

@scaramallion
Copy link
Member

scaramallion commented Sep 15, 2018

For compressed pixel data that will be written decompressed:

from pydicom import dcmread

ds = dcmread('IMG00001.dcm')
# 'JPEG Lossless, Non-Hierarchical, First-Order Prediction (Process 14 [Selection Value 1])'
print(ds.file_meta.TransferSyntaxUID.name)
# True
print(ds.file_meta.TransferSyntaxUID.is_compressed)

# Decompress Pixel Data, assuming we have the required dependencies
# Also sets the transfer syntax UID and the element length
ds.decompress()
# False
print(ds.file_meta.TransferSyntaxUID.is_compressed)

ds.save_as('out.dcm')

For compressed pixel data that has been modified and will be written compressed:

from pydicom import dcmread
from pydicom.encaps import encapsulate

ds = dcmread('IMG00001.dcm')

# Decompress and modify Pixel Data, assuming we have the required dependencies
arr = ds.pixel_array  
arr = some_function_that_modifies_arr(arr)

# Compress the Pixel Data, outside scope of pydicom
#   assumes that the results of the compression is a list of bytes, 
#   each item being the compressed data from a single frame
pixel_data = some_function_that_compresses_arr(arr)  
# Write encapsulated and compressed data back to Pixel Data
ds.PixelData = encapsulate(pixel_data )  
# Update the transfer syntax with whatever syntax matches the compressed data
ds.file_meta.TransferSyntaxUID = WhateverTransferSyntax  

ds.save_as('out.dcm')

@vsoch
Copy link
Member Author

vsoch commented Sep 15, 2018

This is exactly the fix that we need! I simply added this check to the save function (and I think) it's working!

dicom = read_file(dicom_file, force=False)
dicom.file_meta.TransferSyntaxUID.is_compressed is True:
    dicom.decompress()

# cleaned is uint8 numpy array that we've been messing with
dicom.PixelData = cleaned.tostring()
dicom.save_as('/home/vanessa/Desktop/cleaned.dcm')

@fimafurman I will have a PR for you to test in a few minutes for deid.

@fimafurman
Copy link

fimafurman commented Sep 15, 2018 via email

@vsoch
Copy link
Member Author

vsoch commented Sep 15, 2018

okay ready for testing! pydicom/deid#67

When everything looks good over there, I'll take care of closing this issue too.

@vsoch
Copy link
Member Author

vsoch commented Sep 16, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants