diff --git a/DIDKit/App/app.cpp b/DIDKit/App/app.cpp index d69afd3..fbb8900 100644 --- a/DIDKit/App/app.cpp +++ b/DIDKit/App/app.cpp @@ -5,20 +5,37 @@ #include #include #include +#include "IO/Convert/DICOMToBMPConverter.h" +#include "IO/Convert/DICOMToPNGConverter.h" +#include "IO/Convert/DICOMToJPEGConverter.h" #include "DIDMainWindow.h" int main(int argc, char* argv[]) { - QTextCodec* codec = QTextCodec::codecForName("GB2312"); - QTextCodec::setCodecForLocale(codec); + DICOMToBMPConverter converter; + converter.setOutputSize(300, 300); + converter.setFrame(2); + converter.setInputDICOMFile("F:\\Kinds Data Files\\MultiFrame\\MultiFrame_Anon.dcm"); - QApplication a(argc, argv); - - QFont font; - font.setFamily(QString::fromUtf8("Arial")); - QApplication::setFont(font); - - DIDMainWindow w; - w.show(); - return a.exec(); + converter.save("D:\\test.bmp"); + DICOMToPNGConverter pconverter; + pconverter.setOutputSize(300, 300); + pconverter.setInputDICOMFile("D:\\TestData\\CT\\4905\\a8c5c508-06b8-11ea-9b1e-509a4c8d26e3_08870001_4905_10903_287571"); + pconverter.save("D:\\test.png"); + DICOMToJPEGConverter jconverter; + jconverter.setOutputSize(300, 300); + jconverter.setInputDICOMFile("D:\\TestData\\CT\\4905\\a8c5c508-06b8-11ea-9b1e-509a4c8d26e3_08870001_4905_10903_287571"); + jconverter.save("D:\\test.jpg"); +// QTextCodec* codec = QTextCodec::codecForName("GB2312"); +// QTextCodec::setCodecForLocale(codec); +// +// QApplication a(argc, argv); +// +// QFont font; +// font.setFamily(QString::fromUtf8("Arial")); +// QApplication::setFont(font); +// +// DIDMainWindow w; +// w.show(); +// return a.exec(); } diff --git a/DIDKit/CMakeLists.txt b/DIDKit/CMakeLists.txt index e45b239..95a019e 100644 --- a/DIDKit/CMakeLists.txt +++ b/DIDKit/CMakeLists.txt @@ -34,7 +34,7 @@ target_link_libraries(DIDKit dcm_network) add_dependencies(DIDKit dcm_network) if(${BUILD_DIDKit_APP}) - add_executable(DIDKitApp ${DIDKit_headers} ${DIDKit_cpps} ${DIDKit_App_headers} ${DIDKit_App_cpps} + add_executable(DIDKitApp ${DIDKit_IO_headers} ${DIDKit_IO_cpps} ${DIDKit_App_headers} ${DIDKit_App_cpps} ${DIDKit_PACS_headers} ${DIDKit_PACS_cpps}) target_link_libraries(DIDKitApp ${DCMTK_LIBRARIES}) target_link_libraries(DIDKitApp ${VTK_LIBRARIES}) diff --git a/src/src/IO/Convert/ConverterBase.cpp b/src/src/IO/Convert/ConverterBase.cpp new file mode 100644 index 0000000..e982d48 --- /dev/null +++ b/src/src/IO/Convert/ConverterBase.cpp @@ -0,0 +1,70 @@ +// +// Created by Krad on 2022/9/21. +// + +#include "ConverterBase.h" + +#include +#include +#include +#include + +#include "IO/DICOM/DICOMPixelDataHelper.h" + +void ConverterBase::setOutputSize(int height, int width) { + m_Size[0] = height; + m_Size[1] = width; + m_keepSize = false; +} + +void ConverterBase::setInputDICOMFile(const char *filename) { + m_DICOMFileName = filename; +} + +void ConverterBase::loadDICOMPixelData() { + if (! m_DICOMFileName.empty()){ + m_ImageData = vtkImageData::New(); + if (m_Frame<0){ + DICOMPixelDataHelper::GetRenderedData(m_DICOMFileName.c_str(), + m_ImageData,m_Sample,m_Window[0],m_Window[1]); + } + else{ + DICOMPixelDataHelper::GetMultiFrameRenderedData(m_DICOMFileName.c_str(), + m_ImageData,m_Frame,m_Sample,m_Window[0],m_Window[1]); + } + if (!m_keepSize){ + vtkNewresize; + resize->SetInputData(m_ImageData); + resize->SetInterpolate(true); + resize->SetResizeMethodToOutputDimensions(); + resize->SetOutputDimensions(m_Size[0],m_Size[1], -1); + resize->Update(); + m_ImageData->DeepCopy(resize->GetOutput()); + } + } + +} + +void ConverterBase::setFileName(const char *filename) { + m_OutputFileName = filename; +} + +ConverterBase::~ConverterBase() { + if (m_ImageData){ + m_ImageData->Delete(); + m_ImageData = nullptr; + } +} + +void ConverterBase::setColorImage(int sample) { + m_Sample = sample; +} + +void ConverterBase::setWindow(double windowLevel, double windowWidth) { + m_Window[0] = windowLevel; + m_Window[1] = windowWidth; +} + +void ConverterBase::setFrame(int frame) { + m_Frame = frame; +} diff --git a/src/src/IO/Convert/ConverterBase.h b/src/src/IO/Convert/ConverterBase.h new file mode 100644 index 0000000..09cfe0b --- /dev/null +++ b/src/src/IO/Convert/ConverterBase.h @@ -0,0 +1,41 @@ +// +// Created by Krad on 2022/9/21. +// + +#ifndef OMEGAV_CONVERTERBASE_H +#define OMEGAV_CONVERTERBASE_H + +#include + +class vtkImageData; +class ConverterBase { +public: + ConverterBase() = default; + virtual ~ConverterBase(); + void setOutputSize(int height, int width); + void setInputDICOMFile(const char* filename); + void setFileName(const char* filename); + void setColorImage(int sample); + void setWindow(double windowLevel, double windowWidth); + void setFrame(int frame); + virtual void save(const char* filename){}; +protected: + void loadDICOMPixelData(); + int m_Size[2] = {100,100}; + double m_Window[2] = {128.0,256.0}; + int m_Sample = 1; + int m_Frame = -1; + std::string m_DICOMFileName; + std::string m_OutputFileName; + bool m_keepSize = true; + vtkImageData* GetInputData(){ + return m_ImageData; + } +private: + ConverterBase(const ConverterBase&) = delete; + ConverterBase operator=(const ConverterBase&) = delete; + vtkImageData* m_ImageData = nullptr; +}; + + +#endif //OMEGAV_CONVERTERBASE_H diff --git a/src/src/IO/Convert/DICOMToBMPConverter.cpp b/src/src/IO/Convert/DICOMToBMPConverter.cpp new file mode 100644 index 0000000..9c48f6a --- /dev/null +++ b/src/src/IO/Convert/DICOMToBMPConverter.cpp @@ -0,0 +1,24 @@ +// +// Created by Krad on 2022/9/21. +// +#include "DICOMToBMPConverter.h" + +#include "vtkNew.h" +#include "vtkImageData.h" +#include "vtkBMPWriter.h" + +void DICOMToBMPConverter::save(const char *filename) { + loadDICOMPixelData(); + vtkNew writer; + writer->SetInputData(GetInputData()); + writer->SetFileName(filename); + writer->Update(); +} + +DICOMToBMPConverter::DICOMToBMPConverter() { + +} + +DICOMToBMPConverter::~DICOMToBMPConverter() { + +} diff --git a/src/src/IO/Convert/DICOMToBMPConverter.h b/src/src/IO/Convert/DICOMToBMPConverter.h new file mode 100644 index 0000000..bb2d0bb --- /dev/null +++ b/src/src/IO/Convert/DICOMToBMPConverter.h @@ -0,0 +1,18 @@ +// +// Created by Krad on 2022/9/21. +// + +#ifndef OMEGAV_DICOMTOBMPCONVERTER_H +#define OMEGAV_DICOMTOBMPCONVERTER_H + +#include "ConverterBase.h" + +class DICOMToBMPConverter:public ConverterBase { +public: + DICOMToBMPConverter(); + ~DICOMToBMPConverter(); + void save(const char* filename) override ; +}; + + +#endif //OMEGAV_DICOMTOBMPCONVERTER_H diff --git a/src/src/IO/Convert/DICOMToJPEGConverter.cpp b/src/src/IO/Convert/DICOMToJPEGConverter.cpp new file mode 100644 index 0000000..f452837 --- /dev/null +++ b/src/src/IO/Convert/DICOMToJPEGConverter.cpp @@ -0,0 +1,26 @@ +// +// Created by Krad on 2022/9/21. +// + +#include "DICOMToJPEGConverter.h" + +#include +#include +#include + +DICOMToJPEGConverter::DICOMToJPEGConverter() { + +} + +DICOMToJPEGConverter::~DICOMToJPEGConverter() { + +} + +void DICOMToJPEGConverter::save(const char *filename) { + loadDICOMPixelData(); + vtkNew writer; + writer->SetQuality(m_Quality); + writer->SetInputData(GetInputData()); + writer->SetFileName(filename); + writer->Write(); +} diff --git a/src/src/IO/Convert/DICOMToJPEGConverter.h b/src/src/IO/Convert/DICOMToJPEGConverter.h new file mode 100644 index 0000000..457512b --- /dev/null +++ b/src/src/IO/Convert/DICOMToJPEGConverter.h @@ -0,0 +1,25 @@ +// +// Created by Krad on 2022/9/21. +// + +#ifndef OMEGAV_DICOMTOJPEGCONVERTER_H +#define OMEGAV_DICOMTOJPEGCONVERTER_H +#include "ConverterBase.h" + +class DICOMToJPEGConverter: public ConverterBase { +public: + DICOMToJPEGConverter(); + ~DICOMToJPEGConverter(); + void save(const char* filename) override; + void setQuality(int quality){ + if (quality<0) quality = 0; + if (quality>100) quality = 100; + m_Quality = quality; + } + +private: + int m_Quality = 100; +}; + + +#endif //OMEGAV_DICOMTOJPEGCONVERTER_H diff --git a/src/src/IO/Convert/DICOMToPNGConverter.cpp b/src/src/IO/Convert/DICOMToPNGConverter.cpp new file mode 100644 index 0000000..46650ed --- /dev/null +++ b/src/src/IO/Convert/DICOMToPNGConverter.cpp @@ -0,0 +1,25 @@ +// +// Created by Krad on 2022/9/21. +// + +#include "DICOMToPNGConverter.h" +#include "vtkNew.h" +#include "vtkImageData.h" +#include "vtkPNGWriter.h" + +DICOMToPNGConverter::DICOMToPNGConverter() { + +} + +DICOMToPNGConverter::~DICOMToPNGConverter() { + +} + +void DICOMToPNGConverter::save(const char *filename) { + loadDICOMPixelData(); + vtkNew writer; + writer->SetCompressionLevel(m_CompressionLevel); + writer->SetInputData(GetInputData()); + writer->SetFileName(filename); + writer->Write(); +} diff --git a/src/src/IO/Convert/DICOMToPNGConverter.h b/src/src/IO/Convert/DICOMToPNGConverter.h new file mode 100644 index 0000000..371d573 --- /dev/null +++ b/src/src/IO/Convert/DICOMToPNGConverter.h @@ -0,0 +1,26 @@ +// +// Created by Krad on 2022/9/21. +// + +#ifndef OMEGAV_DICOMTOPNGCONVERTER_H +#define OMEGAV_DICOMTOPNGCONVERTER_H + +#include "ConverterBase.h" + +class DICOMToPNGConverter:public ConverterBase { +public: + DICOMToPNGConverter(); + ~DICOMToPNGConverter(); + void save(const char* filename) override; + void setCompressLevel(int level){ + if (level<0) level = 0; + if (level>9) level = 9; + m_CompressionLevel = level; + } + +private: + int m_CompressionLevel = 5; +}; + + +#endif //OMEGAV_DICOMTOPNGCONVERTER_H diff --git a/src/src/IO/DICOM/DICOMPixelDataHelper.cpp b/src/src/IO/DICOM/DICOMPixelDataHelper.cpp index 3d676ba..c24d56e 100644 --- a/src/src/IO/DICOM/DICOMPixelDataHelper.cpp +++ b/src/src/IO/DICOM/DICOMPixelDataHelper.cpp @@ -3,12 +3,15 @@ // #include "DICOMPixelDataHelper.h" + #include #include #include #include #include #include +#include + #include "ExtendMedicalImageProperties.h" #ifdef OPENJPEG #include "openjpeg-2.3/openjpeg.h" @@ -248,3 +251,47 @@ void DICOMPixelDataHelper::ClearFileObjectCache() { bool DICOMPixelDataHelper::CheckFileObjectCache(const char *path) { return DICOMFileObjectCache::getInstance()->contains(path); } + +bool DICOMPixelDataHelper::GetRenderedData(const char *path, vtkImageData *data,int sample,double windowLevel, double windowWidth) { + DcmFileFormat fileFormat; + if (fileFormat.loadFile(path).good()) { + DcmDataset *dset = fileFormat.getDataset(); + DicomImage dcmImage(&fileFormat, dset->getOriginalXfer(), CIF_MayDetachPixelData); + RenderToImageData(data, sample, windowLevel, windowWidth, dcmImage); + return true; + } + return false; +} + +void DICOMPixelDataHelper::RenderToImageData(vtkImageData *data, int sample, double windowLevel, double windowWidth, + DicomImage &dcmImage) {//flip for vtk writer + dcmImage.flipImage(0,1); + if (sample == 1){ + dcmImage.setWindow(windowLevel, windowWidth); + } + data->SetExtent(0, dcmImage.getWidth()-1,0,dcmImage.getHeight()-1, 0 ,0); + data->AllocateScalars(VTK_UNSIGNED_CHAR,3); + void* d = data->GetScalarPointer(); + dcmImage.createWindowsDIB(d,dcmImage.getWidth()*dcmImage.getHeight()*3 ); +} + +bool DICOMPixelDataHelper::GetMultiFrameRenderedData(const char *path, vtkImageData *data, int sample, int frame, + double windowLevel, double windowWidth) { + auto fileFormat = DICOMFileObjectCache::getInstance()->GetFileObject(path); + if (!fileFormat){ + fileFormat = new DcmFileFormat; + if (fileFormat->loadFile(path).good() && fileFormat->loadAllDataIntoMemory().good()) { + DICOMFileObjectCache::getInstance()->store(path,fileFormat); + DicomImage dcmImage(fileFormat, fileFormat->getDataset()->getOriginalXfer(), CIF_UsePartialAccessToPixelData, + frame, 1); + if (dcmImage.getStatus() == EIS_Normal) { + RenderToImageData(data, sample, windowLevel, windowWidth, dcmImage); + delete fileFormat; + return true; + } + } + } + delete fileFormat; + return false; + +} diff --git a/src/src/IO/DICOM/DICOMPixelDataHelper.h b/src/src/IO/DICOM/DICOMPixelDataHelper.h index 9bd8b55..6b3fd0d 100644 --- a/src/src/IO/DICOM/DICOMPixelDataHelper.h +++ b/src/src/IO/DICOM/DICOMPixelDataHelper.h @@ -5,8 +5,10 @@ #ifndef OMEGAV_DICOMPIXELDATAHELPER_H #define OMEGAV_DICOMPIXELDATAHELPER_H -class ExtendMedicalImageProperties; +#include +class ExtendMedicalImageProperties; +class vtkImageData; /** * DICOM file Pixel Data read helper */ @@ -18,6 +20,9 @@ public: } static void GetThumbnailData(ExtendMedicalImageProperties *property, void*& data, unsigned long& length,int& sample); + + static bool GetRenderedData(const char * path, vtkImageData* data, int sample, double windowLevel, double windowWidth); + static bool GetMultiFrameRenderedData(const char * path, vtkImageData* data, int sample,int frame, double windowLevel, double windowWidth); /** * Get Pixel Data with Rescaled, result is calculate as integer, and arrange as integer. * @param path dcm file absolute path @@ -97,6 +102,9 @@ public: * Finalize decompress Codecs, must be called after other method have done. */ static void FinalizeCodecs(); + + static void + RenderToImageData(vtkImageData *data, int sample, double windowLevel, double windowWidth, DicomImage &dcmImage); };