diff --git a/DIDKit/App/app.cpp b/DIDKit/App/app.cpp index fbb8900..7adb77c 100644 --- a/DIDKit/App/app.cpp +++ b/DIDKit/App/app.cpp @@ -9,9 +9,17 @@ #include "IO/Convert/DICOMToPNGConverter.h" #include "IO/Convert/DICOMToJPEGConverter.h" +#include "IO/DICOM/MultiframeDICOMSpliter.h" + #include "DIDMainWindow.h" int main(int argc, char* argv[]) { + MultiframeDICOMSpliter spliter; + spliter.SetInputFileName("F:\\Special DICOM\\112255\\b65b0956-c046-11ea-a50f-509a4c8d26e3_08870001_37445_112255_7328989.dcm"); + spliter.SetOutputDirPath("D:\\mounttest"); + spliter.SetOutputFilePattern("%d.dcm"); + spliter.write(); + return 0; DICOMToBMPConverter converter; converter.setOutputSize(300, 300); converter.setFrame(2); @@ -19,6 +27,7 @@ int main(int argc, char* argv[]) { converter.save("D:\\test.bmp"); DICOMToPNGConverter pconverter; + pconverter.setFrame(2); pconverter.setOutputSize(300, 300); pconverter.setInputDICOMFile("D:\\TestData\\CT\\4905\\a8c5c508-06b8-11ea-9b1e-509a4c8d26e3_08870001_4905_10903_287571"); pconverter.save("D:\\test.png"); diff --git a/src/src/IO/DICOM/MultiframeDICOMSpliter.cpp b/src/src/IO/DICOM/MultiframeDICOMSpliter.cpp new file mode 100644 index 0000000..b9b503e --- /dev/null +++ b/src/src/IO/DICOM/MultiframeDICOMSpliter.cpp @@ -0,0 +1,204 @@ +// +// Created by Krad on 2022/9/22. +// + +#include +#include "MultiframeDICOMSpliter.h" +#include "dcmtk/dcmdata/dcfilefo.h" +#include "dcmtk/dcmdata/dcdeftag.h" +#include "dcmtk/dcmdata/dcdatset.h" +#include "dcmtk/dcmdata/dcspchrs.h" +namespace { + const int BUFF_SIZE= 1024; + char buff[BUFF_SIZE]; +} +void MultiframeDICOMSpliter::SetInputFileName(const char *filename) { + mInputFilename = filename; +} + +void MultiframeDICOMSpliter::SetOutputFilePattern(const char *format) { + mOutputFilePattern.clear(); + mOutputFilePattern.append("%s\\"); + mOutputFilePattern.append(format); +} + +void MultiframeDICOMSpliter::SetOutputDirPath(const char *dir) { + mOutputDirPath = dir; +} + +void MultiframeDICOMSpliter::write() { + DcmFileFormat fileFormat; + if (fileFormat.loadFile(mInputFilename).good()){ + DcmDataset* dataset = fileFormat.getDataset(); + dataset->loadAllDataIntoMemory(); + DcmDataset* newDs = (DcmDataset*)dataset->clone(); + // remove frame about tags + DcmElement* e = nullptr; + newDs->findAndDeleteElement(DCM_NumberOfFrames); + newDs->findAndDeleteElement(DCM_SharedFunctionalGroupsSequence); + newDs->findAndDeleteElement(DCM_PerFrameFunctionalGroupsSequence); + newDs->findAndDeleteElement(DCM_FrameDimensionPointer); + newDs->findAndDeleteElement(DCM_FrameIncrementPointer); + newDs->findAndDeleteElement(DCM_FrameTime); + newDs->findAndDeleteElement(DCM_FrameTimeVector); + newDs->findAndDeleteElement(DCM_ConcatenationUID); + newDs->findAndDeleteElement(DCM_ConcatenationFrameOffsetNumber); + newDs->findAndDeleteElement(DCM_InConcatenationNumber); + newDs->findAndDeleteElement(DCM_StereoPairsPresent); + newDs->findAndDeleteElement(DCM_RepresentativeFrameNumber); + newDs->findAndDeleteElement(DCM_RepresentativeFrameNumber); + newDs->findAndDeleteElement(DCM_DimensionOrganizationSequence); + Uint8* d = nullptr; + newDs->putAndInsertUint8Array(DCM_PixelData, d,0); + + std::string SOPInstanceUID; + dataset->findAndGetOFString(DCM_SOPInstanceUID,SOPInstanceUID); + + //multi-frame data + long frameCount = 0; + auto frameRet = dataset->findAndGetSint32(DCM_NumberOfFrames, frameCount); + if (frameRet.good()) { + DcmItem* sharedGroup = nullptr; + if (dataset->findAndGetSequenceItem(DCM_SharedFunctionalGroupsSequence, sharedGroup, 0).good()) { + DcmItem* pixelMeasure = nullptr; + if (sharedGroup->findAndGetSequenceItem(DCM_PixelMeasuresSequence,pixelMeasure, 0).good()){ + // use frame pixel spacing + double spacing[3] = {.0, .0, .0}; + if(pixelMeasure->findAndGetFloat64(DCM_PixelSpacing,spacing[0],0).good()){ + pixelMeasure->findAndGetFloat64(DCM_PixelSpacing,spacing[1],1); + snprintf(buff,BUFF_SIZE, "%f\\%f", spacing[0],spacing[1]); + newDs->putAndInsertString(DCM_PixelSpacing,buff); + } + + // try get frame thickness + if (pixelMeasure->findAndGetFloat64(DCM_SliceThickness,spacing[2]).good()){ + snprintf(buff,BUFF_SIZE, "%f", spacing[2]); + newDs->putAndInsertString(DCM_SliceThickness,buff); + } + if (pixelMeasure->findAndGetFloat64(DCM_SpacingBetweenSlices,spacing[2]).good()){ + snprintf(buff,BUFF_SIZE, "%f", spacing[2]); + newDs->putAndInsertString(DCM_SliceThickness,buff); + } + } + + // try to get frame window setting + DcmItem* frameLUT = nullptr; + if (sharedGroup->findAndGetSequenceItem(DCM_FrameVOILUTSequence,frameLUT, 0).good()){ + double window[2] = {.0, .0}; + + if (frameLUT->findAndGetFloat64(DCM_WindowCenter,window[0]).good()){ + frameLUT->findAndGetFloat64(DCM_WindowWidth,window[1]); + + snprintf(buff,BUFF_SIZE, "%f", window[0]); + newDs->putAndInsertString(DCM_WindowCenter,buff); + snprintf(buff,BUFF_SIZE, "%f", window[1]); + newDs->putAndInsertString(DCM_WindowWidth,buff); + } + } + } + long instanceNumber = 0; + dataset->findAndGetSint32(DCM_InstanceNumber, instanceNumber); + for (int i = 0; i < frameCount; ++i) { + DcmDataset frameDs(*newDs); + DcmItem *perFrameGroup = nullptr; + if (dataset->findAndGetSequenceItem(DCM_PerFrameFunctionalGroupsSequence, + perFrameGroup, i).good()) { + //calc instance number for frame + DcmItem *frameContent = nullptr; + if (perFrameGroup->findAndGetSequenceItem(DCM_FrameContentSequence, + frameContent, 0).good()) { + unsigned long frameNumber = 0; + frameContent->findAndGetUint32(DCM_InStackPositionNumber, frameNumber); + int newInstanceNumber = (int)(frameNumber + instanceNumber); + snprintf(buff,BUFF_SIZE, "%d", newInstanceNumber); + frameDs.putAndInsertString(DCM_InstanceNumber, buff); + std::string newSOPInstanceUID ; + newSOPInstanceUID.append(SOPInstanceUID); + snprintf(buff,BUFF_SIZE, ".%d", newInstanceNumber); + newSOPInstanceUID.append(buff); + frameDs.putAndInsertString(DCM_SOPInstanceUID, newSOPInstanceUID.c_str()); + } + + // try to get frame position + DcmItem *framePosition = nullptr; + if (perFrameGroup->findAndGetSequenceItem(DCM_PlanePositionSequence, + framePosition, 0).good()) { + double position[3] = {.0, .0, .0}; + if (framePosition->findAndGetFloat64(DCM_ImagePositionPatient, + position[0], 0).good()) { + framePosition->findAndGetFloat64(DCM_ImagePositionPatient, + position[1], 1); + framePosition->findAndGetFloat64(DCM_ImagePositionPatient, + position[2], 2); + snprintf(buff,BUFF_SIZE, "%f\\%f\\%f", position[0], position[1], position[2]); + frameDs.putAndInsertString(DCM_ImagePositionPatient,buff); + } + } + + // try to get frame orientation + DcmItem *frameOrientation = nullptr; + if (perFrameGroup->findAndGetSequenceItem(DCM_PlaneOrientationSequence, frameOrientation, + 0).good()) { + double orientation[6] = {.0, .0, .0, .0, .0, .0}; + if (frameOrientation->findAndGetFloat64(DCM_ImageOrientationPatient, + orientation[0], 0).good()) { + frameOrientation->findAndGetFloat64(DCM_ImageOrientationPatient, + orientation[1], 1); + frameOrientation->findAndGetFloat64(DCM_ImageOrientationPatient, + orientation[2], 2); + frameOrientation->findAndGetFloat64(DCM_ImageOrientationPatient, + orientation[3], 3); + frameOrientation->findAndGetFloat64(DCM_ImageOrientationPatient, + orientation[4], 4); + frameOrientation->findAndGetFloat64(DCM_ImageOrientationPatient, + orientation[5], 5); + if(!frameDs.tagExists(DCM_ImageOrientationPatient)){ + frameDs.insertEmptyElement(DCM_ImageOrientationPatient); + } + snprintf(buff,BUFF_SIZE, "%f\\%f\\%f\\%f\\%f\\%f", orientation[0], orientation[1], orientation[2] + , orientation[3], orientation[4], orientation[5]); + frameDs.putAndInsertString(DCM_ImageOrientationPatient,buff); + } + } + } + else{ + int newInstanceNumber = (int)(i + instanceNumber); + snprintf(buff,BUFF_SIZE, "%d", newInstanceNumber); + frameDs.putAndInsertString(DCM_InstanceNumber, buff); + std::string newSOPInstanceUID ; + newSOPInstanceUID.append(SOPInstanceUID); + snprintf(buff,BUFF_SIZE, ".%d", newInstanceNumber); + newSOPInstanceUID.append(buff); + frameDs.putAndInsertString(DCM_SOPInstanceUID, newSOPInstanceUID.c_str()); + } + DicomImage dcmImage(&fileFormat, dataset->getOriginalXfer(), CIF_UsePartialAccessToPixelData, + i, 1); + if (dcmImage.getStatus() == EIS_Normal) { + const DiPixel *pixelData = dcmImage.getInterData();//rescaled + const void *dd = pixelData->getData(); + unsigned long length = pixelData->getCount(); + unsigned long dataBits = 1; + switch (pixelData->getRepresentation()) { + case EPR_Uint8: + case EPR_Sint8: + break; + case EPR_Uint16: + case EPR_Sint16: + dataBits = 2; + break; + case EPR_Uint32: + case EPR_Sint32: + dataBits = 4; + break; + } + length= length*dataBits; + frameDs.putAndInsertUint8Array(DCM_PixelData, (Uint8*) dd, length); + DcmFileFormat newOne(&frameDs); + char buff[200]={0}; + sprintf(buff,mOutputFilePattern.c_str(),mOutputDirPath.c_str(),i); + newOne.saveFile(buff); + } + } + } + } +} diff --git a/src/src/IO/DICOM/MultiframeDICOMSpliter.h b/src/src/IO/DICOM/MultiframeDICOMSpliter.h new file mode 100644 index 0000000..a7b7c59 --- /dev/null +++ b/src/src/IO/DICOM/MultiframeDICOMSpliter.h @@ -0,0 +1,24 @@ +// +// Created by Krad on 2022/9/22. +// + +#ifndef OMEGAV_MULTIFRAMEDICOMSPLITER_H +#define OMEGAV_MULTIFRAMEDICOMSPLITER_H + +#include + +class MultiframeDICOMSpliter { +public: + void SetInputFileName(const char* filename); + void SetOutputFilePattern(const char* format); + void SetOutputDirPath(const char* dir); + void write(); + +private: + std::string mInputFilename; + std::string mOutputFilePattern; + std::string mOutputDirPath; +}; + + +#endif //OMEGAV_MULTIFRAMEDICOMSPLITER_H