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.

Any suggestion is appreciated~~~


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 has 3 components
                double pos[3];
                for (i = 0; i < 3; ++i) {
    
                    // findAndGetFloat64 automatically converts the strings to double
                    if (!item->findAndGetFloat64(DCM_ImagePositionPatient, pos, i, /*searchIntoSub=*/OFTrue ).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 at least better error handling, you will probably directly access the tag in the containing sequence instead of recursively searching for it, and of course save the position somewhere sensible.