Add multi-frame data Spliter
This commit is contained in:
204
src/src/IO/DICOM/MultiframeDICOMSpliter.cpp
Normal file
204
src/src/IO/DICOM/MultiframeDICOMSpliter.cpp
Normal file
@@ -0,0 +1,204 @@
|
||||
//
|
||||
// Created by Krad on 2022/9/22.
|
||||
//
|
||||
|
||||
#include <dcmtk/dcmimgle/dcmimage.h>
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
24
src/src/IO/DICOM/MultiframeDICOMSpliter.h
Normal file
24
src/src/IO/DICOM/MultiframeDICOMSpliter.h
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// Created by Krad on 2022/9/22.
|
||||
//
|
||||
|
||||
#ifndef OMEGAV_MULTIFRAMEDICOMSPLITER_H
|
||||
#define OMEGAV_MULTIFRAMEDICOMSPLITER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user