Add multi-frame data Spliter
This commit is contained in:
@@ -9,9 +9,17 @@
|
|||||||
#include "IO/Convert/DICOMToPNGConverter.h"
|
#include "IO/Convert/DICOMToPNGConverter.h"
|
||||||
#include "IO/Convert/DICOMToJPEGConverter.h"
|
#include "IO/Convert/DICOMToJPEGConverter.h"
|
||||||
|
|
||||||
|
#include "IO/DICOM/MultiframeDICOMSpliter.h"
|
||||||
|
|
||||||
#include "DIDMainWindow.h"
|
#include "DIDMainWindow.h"
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
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;
|
DICOMToBMPConverter converter;
|
||||||
converter.setOutputSize(300, 300);
|
converter.setOutputSize(300, 300);
|
||||||
converter.setFrame(2);
|
converter.setFrame(2);
|
||||||
@@ -19,6 +27,7 @@ int main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
converter.save("D:\\test.bmp");
|
converter.save("D:\\test.bmp");
|
||||||
DICOMToPNGConverter pconverter;
|
DICOMToPNGConverter pconverter;
|
||||||
|
pconverter.setFrame(2);
|
||||||
pconverter.setOutputSize(300, 300);
|
pconverter.setOutputSize(300, 300);
|
||||||
pconverter.setInputDICOMFile("D:\\TestData\\CT\\4905\\a8c5c508-06b8-11ea-9b1e-509a4c8d26e3_08870001_4905_10903_287571");
|
pconverter.setInputDICOMFile("D:\\TestData\\CT\\4905\\a8c5c508-06b8-11ea-9b1e-509a4c8d26e3_08870001_4905_10903_287571");
|
||||||
pconverter.save("D:\\test.png");
|
pconverter.save("D:\\test.png");
|
||||||
|
|||||||
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