dicomdcmtk

How to read the per-frame info from a multi-frame dicom


I am using dcmtk to read a dicom. This dicom file contains 100 image. Each image has a PatientPosition. How can I get these 100 PatientPosition?

If DicomImage can provide the 100 PatientPosition? If findAndGetSequenceItem can provide the 100 PatientPosition? Hope some c++ code to fetch 100 PatientPosition.


Solution

  • I assume that you are referring to an enhanced DICOM object (e.g. Enhanced CT Image, Enhanced MR Image or the like). In this case the frame-specific tags can be found in the Per-Frame Functional Group Sequence (the link show the reference for an Enhanced MR Image). Each item of the sequence refers to a separate frame.

    I also assume that by PatientPosition you actually mean PatientPositionPatient, which would be the related tag for MR, CT and a few other types of images, but the handling of frame-specific tags is the same regardless of the tag. Each frame-specific tag is embedded into another sequence, which groups together related tags - in the case of PatientPositionPatient this is the Plane Position Sequence. As dcmtk allows to search for tags recursively in sub-sequences, you even don't have to know that - it is enough to search for the tag in the relevant sequence item:

    auto dcmFile = new DcmFileFormat;
    auto cond = dcmFile->loadFile(filePath);
    if (cond.good()) {
    
        // load the dataset from the DICOM file
        auto* dataset = dcmFile->getDataset();
        DcmSequenceOfItems* sequence;
    
        // search for the per-frame functional groups sequence
        OFResult result = dataset->findAndGetSequence(DCM_PerFrameFunctionalGroupsSequence, sequence);
        if (result.good() && sequence && !sequence->isEmpty()) {
    
            // iterate over all items until none remains
            // this will correspond to the number of frames
            for (int frameNr = 0;; ++frameNr) {
                auto* item = sequence->getItem(frame); 
                if (!item) { // could instead get NumberOfFrames first
                    break;
                }
    
                // Image Position Patient is inside the Plane Position Sequence
                DcmSequenceOfItems* planePositionSequence;
                result = item->findAndGetSequence(DCM_PlanePositionSequence, planePositionSequence);
                if (result.good() && planePositionSequence && !planePositionSequence->isEmpty()) {
                    // Plane Position Sequence has only one item
                    auto* firstItem = planePositionSequence->getItem(0); 
    
                    // Image Position Patient has 3 components
                    double pos[3];
                    for (i = 0; i < 3; ++i) {
    
                        // findAndGetFloat64 automatically converts the strings to double
                        if (!firstItem->findAndGetFloat64(DCM_ImagePositionPatient, pos[i], i).good()) {
                            // do some error handling here  
                        }
                    }
                    // do something sensible with the result
                    std::cout << "Position: " << pos[0] << ", " << pos[1] << ", " << pos[2];
                }
            }
        }
    }
    

    Note that this is just out of my head and may contain errors. In reality, you need to add some error handling, and of course save the position somewhere sensible.