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

Iterate over all tags with an AttributeSelector #415

Open
kaspermarstal opened this issue Sep 12, 2023 · 4 comments
Open

Iterate over all tags with an AttributeSelector #415

kaspermarstal opened this issue Sep 12, 2023 · 4 comments
Labels
A-lib Area: library C-object Crate: dicom-object enhancement help wanted

Comments

@kaspermarstal
Copy link

kaspermarstal commented Sep 12, 2023

Hi, how do I

  1. Build an InMemDicomObject with nested sequences in code?
  2. Iterate over all data elements in the InMemDicomObject (including sequences) whilst keeping track of the path of the data elements? Can I somehow get access to an AttributeSelector and its list of steps when iterating?

Keep up the great work. Very impressive.

@Enet4
Copy link
Owner

Enet4 commented Sep 13, 2023

Thank you for your interest in DICOM-rs!

  1. Build an InMemDicomObject with nested sequences in code?

With the attribute operations API, this is possible by creating an empty sequence first:

// create Scheduled Procedure Step Sequence if it does not exist yet
obj.apply(AttributeOp::new(
     tags::SCHEDULED_PROCEDURE_STEP_SEQUENCE,
     AttributeAction::SetIfMissing(PrimitiveValue::Empty),
))?;

// set Scheduled Procedure Step Sequence -> Modality
obj.apply(AttributeOp::new(
     (tags::SCHEDULED_PROCEDURE_STEP_SEQUENCE, tags::MODALITY),
     AttributeAction::Set(PrimitiveValue::from("CT")),
))?;

The ergonomics of this could be improved in the future, so that the first step is no longer necessary.

The alternative without AttributeOp is to construct the data set sequence manually and then insert it onto the DICOM object

obj.put(DataElement::new(
    tags::SHEDULED_PROCEDURE_STEP_SEQUENCE,
    VR::SQ,
    DataSetSequence::from(vec![
        InMemDicomObject::from_element_iter([
            DataElement::new(tags::MODALITY, VR::CS, "CT"),
        ])
    ]),
));
  1. Iterate over all data elements in the InMemDicomObject (including sequences) whilst keeping track of the path of the data elements? Can I somehow get access to an AttributeSelector and its list of steps when iterating?

There is only an implementation for iteration over the root data set elements, which does not provide the corresponding attribute selectors, nor does it traverse recursively into nested data sets. I agree that it would be interesting to experiment with this. I will use this issue to track this capability.
Would you be interested in working on this, with a bit of mentoring?

@Enet4 Enet4 added enhancement A-lib Area: library C-object Crate: dicom-object labels Sep 13, 2023
@kaspermarstal
Copy link
Author

Sure. I'll let you know when I have the time (need to finish this first).

@naterichman
Copy link
Contributor

Not sure if this helps, but I had a need to do that recently and this is what I came up with:

fn get_all_entries(
    file: &DefaultDicomObject    
) -> Result<Vec<AttributeSelector>, ReadError> {

    let mut all_paths = Vec::<Vec<AttributeSelectorStep>>::new();
    file.iter().for_each(|element|
        process_entry(&element, Vec::new(), &mut all_paths, &mut leafs)
    );
    let all_paths = all_paths
        .into_iter()
        .map(|e| AttributeSelector::new(e))
        .collect::<Option<Vec<_>>>()
        .ok_or(ReadError::DicomError(DicomReadError::Other("Could not create attribute selector".to_string())))?;
    Ok(all_paths)
}

fn process_entry(
    de: &InMemElement,
    mut path: Vec<AttributeSelectorStep>,
    all_paths: &mut Vec<Vec<AttributeSelectorStep>>,
) {
    let tag = de.header().tag;

    match de.value() {
        DicomValue::Primitive(_v) => {
            // Push the full path
            path.push(AttributeSelectorStep::Tag(tag));
            all_paths.push(path);
        },
        DicomValue::Sequence(v) => {
            let mut path = path.clone();
            for (num, ds) in v.items().iter().enumerate() {
                path.push(AttributeSelectorStep::Nested{
                    tag: tag,
                    item: num as u32
                });
                for el in ds.iter() {
                    process_entry(el, path.clone(), all_paths);
                }
            }
        },
        DicomValue::PixelSequence(_v) => return
    }
}

@kaspermarstal
Copy link
Author

Thanks for taking your time to post this @naterichman!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lib Area: library C-object Crate: dicom-object enhancement help wanted
Projects
None yet
Development

No branches or pull requests

3 participants