205 lines
11 KiB
C++
205 lines
11 KiB
C++
|
|
//
|
||
|
|
// 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);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|