Combining multiple images into single multi-frame

All other questions regarding DCMTK

Moderator: Moderator Team

Post Reply
Message
Author
curquhart
Posts: 2
Joined: Tue, 2020-07-21, 09:32

Combining multiple images into single multi-frame

#1 Post by curquhart »

I'm new to the health domain and DICOM. I've used dcmtk to do basic stuff such as opening and updating instances from files and streams.

But now I need to take multiple images from disk which are in the same series but should be a single multi-frame file. I've obviously Googled but now I find myself getting lost in DcmPixelItem, DcmPixelSequence and DcmPixelData classes.

I'm probably going about this completely wrong, and there may be more information required before you can provide an answer, but here's the code:

Code: Select all


DcmPixelSequence * mergedPixelSequence = new DcmPixelSequence(DcmTagKey{ DCM_PixelData });
shared_ptr<DcmFileFormat> mergedInstance = std::make_shared<DcmFileFormat>();

DcmDataset * mergedDataset = mergedInstance->getDataset();

E_TransferSyntax xferSyntax = EXS_Unknown;

// for each separate image instance, add it to the 'merged' multi-frame instance
for (const auto& instance : series.second->getInstances())
{
  DcmDataset* ds = instance->dataset->dcmFile->getDataset();

  DcmElement * element = nullptr;                        
  if (instance->dataset->dcmFile->getDataset()->findAndGetElement(DcmTagKey{ DCM_PixelData }, element).good())
  {
    if (element)
    {   
      const DcmRepresentationParameter* rep = NULL;
      // Find the key that is needed to access the right representation of the data within DCMTK
      DcmPixelData * pixelElement = OFstatic_cast(DcmPixelData*, element);
      pixelElement->getOriginalRepresentationKey(xferSyntax, rep);

      DcmPixelSequence * dseq = NULL;
      OFCondition status = pixelElement->getEncapsulatedRepresentation(xferSyntax, rep, dseq);

      if (status.good())
      {
        DcmPixelItem * pixitem = NULL;
        // Access first frame (skipping offset table)
        dseq->getItem(pixitem, 1);

        if (pixitem)
        {
          mergedPixelSequence->insert(pixitem);
        }                                    
      }
    }                            
  }
}

if (mergedDataset && mergedPixelSequence)
{
    mergedDataset->insert(mergedPixelSequence);
}

stringstream ss;
ss << "d:\\target\\" << mergedSeriesId << ".dcm";

const OFCondition fileWriteStatus = mergedInstance->saveFile(ss.str().c_str());

if (!fileWriteStatus.good())
{
    logg(fileWriteStatus.text());  // This outputs "Illegal call, perhaps wrong parameters"
}
The fileWriteStatus returned by saveFile() has error text: "Illegal call, perhaps wrong parameters"


Thanks

Michael Onken
DCMTK Developer
Posts: 2048
Joined: Fri, 2004-11-05, 13:47
Location: Oldenburg, Germany
Contact:

Re: Combining multiple images into single multi-frame

#2 Post by Michael Onken »

Hi,

I think the best approach is to look into the dcmcjpeg application or more exactly, into the class that handles the encoding in dcmjpeg/libsrc/djcodece.cc. Look for example into DJCodecEncoder::encodeColorImage(...) that shows how you can construct a pixel sequence from scratch.

Best regards,
Michael

curquhart
Posts: 2
Joined: Tue, 2020-07-21, 09:32

Re: Combining multiple images into single multi-frame

#3 Post by curquhart »

Hi
Thanks, pointing me to that source file helped.

Callum

W774937253
Posts: 1
Joined: Tue, 2021-08-31, 08:36

Re: Combining multiple images into single multi-frame

#4 Post by W774937253 »

hi,
have you solve this problem?
i think i have the same thing which is to convert 3D array like 1024*1024*120(size) data to a single multi-frame dicom file.
here is my test code, it can save a .dcm file, but opened it with Radiant, it didn't work yet~~


char studydate[] = { "20210822" };
char studytime[] = { "141523" };
char uid[100];
DcmFileFormat fileFormat;
DcmDataset *dataset = fileFormat.getDataset();
char impClassUID[] = { "1.20.840.1.114380" };

OFCondition status;
status = dataset->putAndInsertString(DCM_SOPClassUID, UID_SecondaryCaptureImageStorage);
checkStatusAndNum(status, dataset);
status = dataset->putAndInsertString(DCM_SOPInstanceUID, dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT));
checkStatusAndNum(status, dataset);

status = dataset->putAndInsertString(DCM_TransferSyntaxUID, UID_LittleEndianExplicitTransferSyntax);
checkStatusAndNum(status, dataset);

status = dataset->putAndInsertString(DCM_SourceApplicationEntityTitle, "IVUS SCU");
checkStatusAndNum(status, dataset);
status = dataset->putAndInsertString(DCM_SpecificCharacterSet, "ISO_IR 100");
checkStatusAndNum(status, dataset);
status = dataset->putAndInsertString(DCM_ImageType, "ORIGINAL\\SECONDARY");
checkStatusAndNum(status, dataset);


SYSTEMTIME sys;
GetLocalTime(&sys);
std::stringstream date, time;
date << sys.wYear << sys.wMonth << sys.wDay;
time << sys.wHour << sys.wMinute << sys.wSecond;
std::string instanceCreateDate = date.str();
std::string instanceCreateTime = time.str();

status = dataset->putAndInsertString(DCM_InstanceCreationDate, instanceCreateDate.c_str());
checkStatusAndNum(status, dataset);

status = dataset->putAndInsertString(DCM_InstanceCreationTime, instanceCreateTime.c_str());
checkStatusAndNum(status, dataset);
status = dataset->putAndInsertString(DCM_StudyDate, studydate);
checkStatusAndNum(status, dataset);
status = dataset->putAndInsertString(DCM_StudyTime, studytime);
checkStatusAndNum(status, dataset);
std::string acquisitionDataTime = std::string(studydate) + std::string(studytime);
status = dataset->putAndInsertString(DCM_AcquisitionDateTime, acquisitionDataTime.c_str());
checkStatusAndNum(status, dataset);
status = dataset->putAndInsertString(DCM_AcquisitionDate, studydate);
checkStatusAndNum(status, dataset);

char snapshotData[] = { "20210826" };
char snapshotTime[] = { "181459" };
status = dataset->putAndInsertString(DCM_ContentDate, snapshotData);
checkStatusAndNum(status, dataset);
status = dataset->putAndInsertString(DCM_ContentTime, snapshotTime);
checkStatusAndNum(status, dataset);

status = dataset->putAndInsertString(DCM_StudyInstanceUID, dcmGenerateUniqueIdentifier(uid, SITE_STUDY_UID_ROOT));
checkStatusAndNum(status, dataset);

status = dataset->putAndInsertString(DCM_SeriesInstanceUID, dcmGenerateUniqueIdentifier(uid, SITE_SERIES_UID_ROOT));
checkStatusAndNum(status, dataset);



status = dataset->putAndInsertString(DCM_Modality, "IVUS");
checkStatusAndNum(status, dataset);

status = dataset->putAndInsertString(DCM_ConversionType, "WSD");
checkStatusAndNum(status, dataset);

status = dataset->putAndInsertString(DCM_Manufacturer, "sonosemi");
checkStatusAndNum(status, dataset);

status = dataset->putAndInsertString(DCM_InstitutionName, "sonosemi");
checkStatusAndNum(status, dataset);
status = dataset->putAndInsertString(DCM_StationName, "sonosemi");
checkStatusAndNum(status, dataset);

status = dataset->putAndInsertString(DCM_SeriesDescription, "RUNS3_IVUS");
checkStatusAndNum(status, dataset);

status = dataset->putAndInsertString(DCM_ManufacturerModelName, "IVUS_Lab");
checkStatusAndNum(status, dataset);


status = dataset->putAndInsertString(DCM_ManufacturerModelName, "IVUS_Lab");
checkStatusAndNum(status, dataset);

std::string patientName("Chen zehao");
status = fileFormat.getDataset()->putAndInsertString(DCM_PatientName, patientName.c_str());
checkStatusAndNum(status, dataset);

std::string patientid("C2021083021");
status = fileFormat.getDataset()->putAndInsertString(DCM_PatientID, patientid.c_str());
checkStatusAndNum(status, dataset);

std::string patienbirthday("19980509");
status = fileFormat.getDataset()->putAndInsertString(DCM_PatientBirthDate, patienbirthday.c_str());
checkStatusAndNum(status, dataset);

std::string patientsex("o");
status = fileFormat.getDataset()->putAndInsertString(DCM_PatientSex, patientsex.c_str());
checkStatusAndNum(status, dataset);


std::string deviceSeriesNumber("10125");
status = fileFormat.getDataset()->putAndInsertString(DCM_DeviceSerialNumber, deviceSeriesNumber.c_str());
checkStatusAndNum(status, dataset);

std::string softworeVersions("2.18.258.364.01");
status = fileFormat.getDataset()->putAndInsertString(DCM_SoftwareVersions, softworeVersions.c_str());
checkStatusAndNum(status, dataset);


status = dataset->putAndInsertString(DCM_StudyID, "895623147");
checkStatusAndNum(status, dataset);

status = dataset->putAndInsertString(DCM_SeriesNumber, "2");
checkStatusAndNum(status, dataset);

status = dataset->putAndInsertString(DCM_InstanceNumber, "2");
checkStatusAndNum(status, dataset);


status = dataset->putAndInsertString(DCM_ImageComments, "run2");
checkStatusAndNum(status, dataset);

DcmItem *sequenceDelimitItem = new DcmItem;
//DcmSequenceOfItems *dimensionOrganizationSeq = new DcmSequenceOfItems(DCM_DimensionOrganizationSequence);
//dimensionOrganizationSeq->append(sequenceDelimitItem);

if (status.good())
{
std::cout << "" << std::endl;
}
DcmItem dimensionSequence;
if (1)
{
status = dimensionSequence.putAndInsertUint16(DCM_SamplesPerPixel, 1);
status = dimensionSequence.putAndInsertString(DCM_PhotometricInterpretation, "MONOCHROME2");
status = dimensionSequence.putAndInsertString(DCM_NumberOfFrames, "10");
status = dimensionSequence.putAndInsertUint16(DCM_Rows, 1024);
status = dimensionSequence.putAndInsertUint16(DCM_Columns, 1024);
status = dimensionSequence.putAndInsertUint16(DCM_BitsAllocated, 8);
status = dimensionSequence.putAndInsertUint16(DCM_BitsStored, 8);
status = dimensionSequence.putAndInsertUint16(DCM_HighBit, 7);
status = dimensionSequence.putAndInsertUint16(DCM_PixelRepresentation, 0);
status = dimensionSequence.putAndInsertString(DCM_LossyImageCompression, "00");
}
sequenceDelimitItem->insertSequenceItem(DCM_DimensionIndexSequence,&dimensionSequence);



//插入图像厚度,像素间距
DcmSequenceOfItems *PixMeasureSeq = new DcmSequenceOfItems(DCM_PixelMeasuresSequence);
DcmItem *pixelItem = new DcmItem();

status = pixelItem->putAndInsertString(DCM_SliceThickness, "0.2");
status = pixelItem->putAndInsertString(DCM_PixelSpacing, "0.2000\0.2000 ");
PixMeasureSeq->append(pixelItem);

DcmItem *sharedGroupItem= new DcmItem();
sharedGroupItem->insert(PixMeasureSeq);

DcmSequenceOfItems *sharedFuncGroupsSeq = new DcmSequenceOfItems(DCM_SharedFunctionalGroupsSequence);
sharedFuncGroupsSeq->append(sharedGroupItem);

sequenceDelimitItem->insert(sharedFuncGroupsSeq);

DcmSequenceOfItems *preframeGroupsequence = new DcmSequenceOfItems(DCM_PerFrameFunctionalGroupsSequence);


for (int i = 0; i < 10; i++)
{

DcmItem *frameItem = new DcmItem;

//插入图像方向
DcmSequenceOfItems *planeOrientationSeq= new DcmSequenceOfItems(DCM_PlaneOrientationSequence);
DcmItem *planItem= new DcmItem;
planItem->putAndInsertString(DCM_ImageOrientationPatient, "1.0\0.0\0.0\0.0\1.0\0.0 ");
planeOrientationSeq->append(planItem);


//插入图像位置
float position = 10 + 0.2*i;
std::string posStr("0/0/");
printf("%.2f", position);
posStr += std::to_string(position);

DcmSequenceOfItems *planePositionSeq = new DcmSequenceOfItems(DCM_PlanePositionSequence);
DcmItem *planePosItem = new DcmItem;
planePosItem->putAndInsertString(DCM_ImagePositionPatient, posStr.c_str());
planePositionSeq->append(planePosItem);

frameItem->insert(planeOrientationSeq);
frameItem->insert(planePositionSeq);



preframeGroupsequence->append(frameItem);
}

status = sequenceDelimitItem->insert(preframeGroupsequence);
if (status.good())
{
std::cout << "" << std::endl;
}


status = dataset->insertSequenceItem(DCM_DimensionOrganizationSequence, sequenceDelimitItem);
checkStatusAndNum(status, dataset);
char *data = new char[1024 * 1024 * 10];
long long int size = 1024 * 1024 * 10;
memset(data, 0, size);

OFCondition rlt = dataset->putAndInsertUint8Array(DCM_PixelData, (Uint8*)data, size);
checkStatusAndNum(status, dataset);
//size = fileFormat.computeGroupLengthAndPadding(E_GrpLenEncoding::EGL_withGL);
// dataset->
size = dataset->getNumberOfValues();
status = fileFormat.saveFile("ivus4.dcm", E_TransferSyntax::EXS_LittleEndianExplicit);
if (status.good())
{
std::cout << "save OK " << std::endl;
}
delete[]data;

Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Bing [Bot], Google [Bot] and 1 guest