From d3febde98147d9164b9257ee760d4e6e33d1efc4 Mon Sep 17 00:00:00 2001 From: Krad Date: Thu, 29 Sep 2022 11:37:37 +0800 Subject: [PATCH] New export logic(with out annotation) --- src/src/Deprecated/Export/dicomexporter.cpp | 546 +++--------------- src/src/Deprecated/Export/dicomexporter.h | 73 +-- src/src/Deprecated/Export/exportoptions.h | 7 +- src/src/IO/Convert/ConverterBase.cpp | 1 - src/src/IO/Convert/DICOMToQImageConverter.cpp | 39 ++ src/src/IO/Convert/DICOMToQImageConverter.h | 27 + src/src/IO/DICOM/DICOMPixelDataHelper.cpp | 86 ++- src/src/IO/DICOM/DICOMPixelDataHelper.h | 7 + src/src/UI/Dialog/exportdialog.cpp | 58 +- src/src/UI/Dialog/exportdialog.h | 10 +- src/src/UI/Dialog/exportdialog.ui | 63 +- .../UI/Widget/ImageView/dicomimageview.cpp | 3 + src/src/UI/Widget/ImageView/dicomimageview.h | 3 + src/src/UI/Window/QDicomViewer.cpp | 2 +- 14 files changed, 314 insertions(+), 611 deletions(-) create mode 100644 src/src/IO/Convert/DICOMToQImageConverter.cpp create mode 100644 src/src/IO/Convert/DICOMToQImageConverter.h diff --git a/src/src/Deprecated/Export/dicomexporter.cpp b/src/src/Deprecated/Export/dicomexporter.cpp index c575ca9..935104e 100644 --- a/src/src/Deprecated/Export/dicomexporter.cpp +++ b/src/src/Deprecated/Export/dicomexporter.cpp @@ -1,7 +1,17 @@ #include "dicomexporter.h" -#include "Common/SeriesImageSet.h" +#include + +#include "IO/DICOM/DICOMPixelDataHelper.h" +#include "IO/Convert/DICOMToQImageConverter.h" + +namespace { + const char* FileExtention[3]={ + "bmp","jpg","png" + }; +} + DicomExporter::DicomExporter(QObject *parent) : QObject(parent), exportedNumber(0) @@ -19,477 +29,101 @@ void DicomExporter::execute(ExportOptions options) return;// to avoid exception } - initVTK(); exportedNumber = 0; totalCount = 0; caculateExportTotalCount();//caculate the total count of file to be exported - - if (exportOptions.exportFileFormat == ExportOptions::FileFormat::Dicom) - { - for (int i = 0; i < exportOptions.inputData.size(); i++) - { - //Note��When the smart pointer points to another variable, it is automatically - //released, you can move it to outside or not. - initDataReader(); - exportDicom(exportOptions.inputData.at(i)); - } + if (exportOptions.slice >= 0){ + if (exportOptions.inputData.empty() + || exportOptions.inputData[0]->GetFileNames().empty()) { + emit exportError(); + return; + } + std::string fileName = exportOptions.inputData[0]->GetFileNames()[exportOptions.slice].first; + long frame = exportOptions.inputData[0]->GetFileNames()[exportOptions.slice].second; + DICOMToQImageConverter convert; + if (frame>=0){ + convert.setFrame(frame); + } + convert.setInputDICOMFile(fileName.c_str()); + convert.setWindow(exportOptions.windowLevel, exportOptions.windowWidth); + if (exportOptions.inputData[0]->GetSamplePerPixel()>1) + { + convert.setColorImage(exportOptions.inputData[0]->GetSamplePerPixel()); + } + convert.save(); + auto img = convert.getQImage(); + bool ret = img->save(QString("%1/%2%3.%4") + .arg(exportOptions.exportDirectory,exportOptions.fileNamePrefix) + .arg(0).arg(getFileExtention()),getFileExtention()); + delete img; + if(ret){ + emit exportFinished(); + } + else{ + emit exportError(); + return; + } } - else - { - for (int i = 0; i < exportOptions.inputData.size(); i++) - { - initDataReader(); - exportPicture(exportOptions.inputData.at(i)); - } + else{ + long successCount = 0; + long processCount = 0; + DICOMPixelDataHelper::InitCodecs(); + for (int i = 0; i < exportOptions.inputData.size(); ++i) { + auto property = exportOptions.inputData[i]; + if (property->GetFileNames().empty())continue; + QString savedir = QString("%1/%2").arg(exportOptions.exportDirectory,property->GetSeriesUID()); + dir.mkpath(savedir); + for (int j = 0; j < property->GetFileNames().size(); ++j) { + std::string fileName = property->GetFileNames()[j].first; + long frame = property->GetFileNames()[j].second; + DICOMToQImageConverter convert; + if (frame>=0){ + convert.setFrame(frame); + } + convert.setInputDICOMFile(fileName.c_str()); + double * window = property->GetNthWindowLevelPreset(0); + convert.setWindow(window[1], window[0]); + if (property->GetSamplePerPixel()>1) + { + convert.setColorImage(property->GetSamplePerPixel()); + } + convert.save(); + auto img = convert.getQImage(); + bool ret = img->save(QString("%1/%2%3.%4") + .arg(savedir,exportOptions.fileNamePrefix) + .arg(j).arg(getFileExtention()),getFileExtention()); + delete img; + if (ret)++successCount; + ++processCount; + emit exportProgress(totalCount,processCount); + } + + } + DICOMPixelDataHelper::FinalizeCodecs(); + DICOMPixelDataHelper::ClearFileObjectCache(); + if(totalCount == successCount){ + emit exportFinished(); + } + else{ + emit exportError(); + } } - emit exportFinished(); + } - -void DicomExporter::initVTK() +const char * DicomExporter::getFileExtention() { - m_glrenWinExport = vtkSmartPointer::New(); - m_glrenWinExport->OffScreenRenderingOn(); - - m_imageViewerExport = vtkSmartPointer::New(); - m_imageViewerExport->SetRenderWindow(m_glrenWinExport); - m_imageViewerExport->SetupInteractor(m_glrenWinExport->GetInteractor()); + return FileExtention[exportOptions.exportFileFormat]; } -void DicomExporter::initDataReader() -{ -// m_gdcmIOExport = ImageIOTypeExport::New(); -// m_itkSeriesReaderExport = SeriesReaderTypeExport::New(); -// m_itkSeriesReaderExport->SetImageIO(m_gdcmIOExport); -// m_itkConnectorExport = ConnectorTypeExport::New(); -// m_inputNamesExport = InputNamesGeneratorTypeExport::New(); -} - - -void DicomExporter::loadDicomFileAndRender(int file_type) -{ -// try -// { -// m_itkSeriesReaderExport->Update(); -// } -// catch (itk::ExceptionObject &excp) { -// std::cerr << "Exception thrown while reading the series" << std::endl; -// std::cerr << excp << std::endl; -// } -// -// m_itkConnectorExport->SetInput(m_itkSeriesReaderExport->GetOutput()); -// m_itkConnectorExport->Update(); -// -// m_imageViewerExport->SetInputData(m_itkConnectorExport->GetOutput()); -// -// m_imageViewerExport->Render(); -// m_imageViewerExport->SetSlice(0); -// -// //m_imageViewerExport->GetRenderer()->ResetCamera(); -// -// -// infinitiViewer *viewer = exportOptions.serie->getImageViewer2(); -// -// if (exportOptions.windowLevel != -1) -// { -// m_imageViewerExport->SetColorLevel(exportOptions.windowLevel); -// } -// -// if (exportOptions.windowWidth != -1) -// { -// m_imageViewerExport->SetColorWindow(exportOptions.windowWidth); -// } -// -// if (exportOptions.cornerAnnotation != ExportOptions::CornerAnnotation::Disabled) -// { -// if (AnnoHelper::IsAnno()) { -// vtkCornerAnnotation* ann = m_imageViewerExport->GetvtkCornerAnnotation(); -// ann->SetMaximumFontSize(20); -// ann->CopyAllTextsFrom(viewer->GetvtkCornerAnnotation()); -// ann->SetText(BOTTOM_LEFT, ""); -// -// std::string lbl_ser_num; -// std::string ser_num; -// itk::GDCMImageIO::GetLabelFromTag(USER_CONFIG::TAG_SERIES_NUMBER, lbl_ser_num); -// m_gdcmIOExport->GetValueFromTag(USER_CONFIG::TAG_SERIES_NUMBER, ser_num); -// m_imageViewerExport->initTopLeftCornerInfo(lbl_ser_num, ser_num); -// } -// } -// -// -// double vup[3]; -// double vup2[3]; -// vtkCamera *oriCamera = viewer->GetRenderer()->GetActiveCamera(); -// double scale = exportOptions.serie->GetExtent(); -// oriCamera->GetViewUp(vup); -// -// vtkCamera *expCamera = m_imageViewerExport->GetRenderer()->GetActiveCamera(); -// expCamera->SetParallelScale(scale); -// expCamera->GetViewUp(vup2); -// expCamera->SetViewUp(vup); -// -// if (FlipExportHelper::GetFlip()) -// { -// expCamera->Azimuth(180); -// m_imageViewerExport->GetRenderer()->ResetCameraClippingRange(); -// -// } -// m_imageViewerExport->GetRenderWindow()->Render(); -} - - - - -void DicomExporter::doExport(int file_type) -{ - if (file_type == SingleFile) - { - exportedNumber++;//image number starts from 1 - QString fileName = exportOptions.exportDirectory + "/" + exportOptions.fileNamePrefix + QString::number(exportedNumber) + getFileExtention(); - writeToFile(fileName); - emit exportProgress(totalCount, exportedNumber); - } - else if(file_type == DirType) - { - int m_MinSliceExport = m_imageViewerExport->GetSliceMin(); - int m_MaxSliceExport = m_imageViewerExport->GetSliceMax(); - - for (int i = m_MinSliceExport; i <= m_MaxSliceExport; i++) - { - m_imageViewerExport->SetSlice(i); - //m_imageViewerExport->Render(); - - exportedNumber++;//image number starts from 1 - QString fileName = exportOptions.exportDirectory + "/" + exportOptions.fileNamePrefix + QString::number(exportedNumber) + getFileExtention(); - writeToFile(fileName); - - emit exportProgress(totalCount, exportedNumber); - } - } - else - { - return; - } -} - - - -void DicomExporter::writeToFile(const QString& fileName) -{ - // Screenshot - vtkSmartPointer windowToImageFilter = vtkSmartPointer::New(); - - windowToImageFilter->SetInput(m_glrenWinExport); -#if VTK_MAJOR_VERSION >= 8 || VTK_MAJOR_VERSION == 8 && VTK_MINOR_VERSION >= 90 - windowToImageFilter->SetScale(2); // image quality -#else - windowToImageFilter->SetMagnification(2); //image quality -#endif - - windowToImageFilter->Update(); - - - switch (exportOptions.exportFileFormat) - { - case ExportOptions::FileFormat::Bmp: - writeToBmpFile(windowToImageFilter, fileName); - break; - - case ExportOptions::FileFormat::Jpeg: - writeToJpgFile(windowToImageFilter, fileName); - break; - - case ExportOptions::FileFormat::Png: - writeToPngFile(windowToImageFilter, fileName); - break; - - case ExportOptions::FileFormat::Tiff: - writeToTiffFile(windowToImageFilter, fileName); - break; - - default: - break; - } -} - -QString DicomExporter::getFileExtention() -{ - QString fileExtention = ".png"; - - switch (exportOptions.exportFileFormat) - { - case ExportOptions::FileFormat::Bmp: - fileExtention = ".bmp"; - break; - - case ExportOptions::FileFormat::Jpeg: - fileExtention = ".jpg"; - break; - - case ExportOptions::FileFormat::Png: - fileExtention = ".png"; - break; - - case ExportOptions::FileFormat::Tiff: - fileExtention = ".tiff"; - break; - - case ExportOptions::FileFormat::Dicom: - fileExtention = ".dcm"; - break; - - default: - break; - } - - return fileExtention; -} - -void DicomExporter::writeToPngFile(vtkSmartPointer windowToImageFilter, const QString& fileName) -{ - QByteArray bafileName = fileName.toLocal8Bit(); - - vtkSmartPointer writer = vtkSmartPointer::New(); - writer->SetFileName(bafileName.data()); - writer->SetInputConnection(windowToImageFilter->GetOutputPort()); - writer->Write(); -} - -void DicomExporter::writeToBmpFile(vtkSmartPointer windowToImageFilter, const QString& fileName) -{ - QByteArray bafileName = fileName.toLocal8Bit(); - - vtkSmartPointer writer = vtkSmartPointer::New(); - writer->SetFileName(bafileName.data()); - writer->SetInputConnection(windowToImageFilter->GetOutputPort()); - writer->Write(); -} - -void DicomExporter::writeToJpgFile(vtkSmartPointer windowToImageFilter, const QString& fileName) -{ - QByteArray bafileName = fileName.toLocal8Bit(); - - vtkSmartPointer writer = vtkSmartPointer::New(); - writer->SetFileName(bafileName.data()); - writer->SetInputConnection(windowToImageFilter->GetOutputPort()); - writer->Write(); -} - -void DicomExporter::writeToTiffFile(vtkSmartPointer windowToImageFilter, const QString& fileName) -{ - QByteArray bafileName = fileName.toLocal8Bit(); - - vtkSmartPointer writer = vtkSmartPointer::New(); - writer->SetFileName(bafileName.data()); - writer->SetInputConnection(windowToImageFilter->GetOutputPort()); - writer->Write(); -} - -void DicomExporter::exportPicture(const QString& fileName) -{ -// int myFileType = NonType; -// -// QFileInfo fileInfo(fileName); -// QDir dir(fileName); -// -// if (fileInfo.isFile()) -// { -// m_itkSeriesReaderExport->SetFileName(fileName.toStdString()); -// -// myFileType = SingleFile; -// } -// else if (dir.exists()) -// { -// m_inputNamesExport->SetInputDirectory(fileName.toStdString()); -// const SeriesReaderTypeExport::FileNamesContainer & filenames = m_inputNamesExport->GetInputFileNames(); -// m_itkSeriesReaderExport->SetFileNames(filenames); -// -// myFileType = DirType; -// } -// -// if (myFileType != NonType) -// { -// loadDicomFileAndRender(myFileType); -// doExport(myFileType); -// } -} - -void DicomExporter::exportDicom(const QString& fileName) -{ -// bool isFileValid = false; -// -// QFileInfo fileInfo(fileName); -// QDir dir(fileName); -// -// if (fileInfo.isFile()) -// { -// m_itkSeriesReaderExport->SetFileName(fileName.toStdString()); -// -// exportSingleDicomFile(fileName); -// } -// else if (dir.exists()) -// { -// m_inputNamesExport->SetInputDirectory(fileName.toStdString()); -// const SeriesReaderTypeExport::FileNamesContainer & filenames = m_inputNamesExport->GetInputFileNames(); -// m_itkSeriesReaderExport->SetFileNames(filenames); -// -// exportDicomDirectory(fileName); -// } -} - -void DicomExporter::exportSingleDicomFile(const QString& fileName) -{ -// try -// { -// m_itkSeriesReaderExport->UpdateLargestPossibleRegion(); -// m_itkSeriesReaderExport->Update(); -// } -// catch (itk::ExceptionObject &excp) { -// std::cerr << "Exception thrown while reading the series" << std::endl; -// std::cerr << excp << std::endl; -// } -// -// exportedNumber++;//image number starts from 1 -// QString exportedName = exportOptions.exportDirectory + "\\" + exportOptions.fileNamePrefix + QString::number(exportedNumber) + ".dcm"; -// QByteArray bafileName = exportedName.toLocal8Bit(); -// -// -// SeriesWriterType::Pointer seriesWriter = SeriesWriterType::New(); -// seriesWriter->SetImageIO(m_gdcmIOExport); -// seriesWriter->SetInput(m_itkSeriesReaderExport->GetOutput()); -// seriesWriter->SetFileName(std::string(bafileName)); -// -// SeriesReaderTypeExport::DictionaryArrayRawPointer dicArray = m_itkSeriesReaderExport->GetMetaDataDictionaryArray(); -// modifyDicomTags(dicArray); -// seriesWriter->SetMetaDataDictionaryArray(dicArray); -// -// try -// { -// seriesWriter->Update(); -// -// emit exportProgress(totalCount, exportedNumber); -// } -// catch (itk::ExceptionObject & excp) -// { -// std::cerr << "Exception thrown while writing the series " << std::endl; -// std::cerr << excp << std::endl; -// } -} - -void DicomExporter::exportDicomDirectory(const QString& fileName) -{ -// try -// { -// m_itkSeriesReaderExport->Update(); -// } -// catch (itk::ExceptionObject &excp) { -// std::cerr << "Exception thrown while reading the series" << std::endl; -// std::cerr << excp << std::endl; -// } -// -// m_inputNamesExport->SetOutputDirectory(exportOptions.exportDirectory.toStdString()); -// -// itk::SerieUIDContainer newOutNames; -// itk::SerieUIDContainer oldOutputNames = m_inputNamesExport->GetOutputFileNames(); -// for (int i = 0; i < oldOutputNames.size(); i++) -// { -// std::string originName = oldOutputNames.at(i); -// QFileInfo fileinfo(QString::fromStdString(originName)); -// QString fName = fileinfo.fileName(); -// QString fPath = fileinfo.absolutePath(); -// -// exportedNumber++;//image number starts from 1 -// QString newName = fPath + "\\" + exportOptions.fileNamePrefix + QString::number(exportedNumber) + ".dcm"; -// QByteArray bafileName = newName.toLocal8Bit(); -// -// newOutNames.push_back(std::string(bafileName)); -// } -// -// SeriesWriterType::Pointer seriesWriter = SeriesWriterType::New(); -// seriesWriter->SetImageIO(m_gdcmIOExport); -// seriesWriter->SetInput(m_itkSeriesReaderExport->GetOutput()); -// seriesWriter->SetFileNames(newOutNames); -// -// SeriesReaderTypeExport::DictionaryArrayRawPointer dicArray = m_itkSeriesReaderExport->GetMetaDataDictionaryArray(); -// modifyDicomTags(dicArray); -// seriesWriter->SetMetaDataDictionaryArray(dicArray); -// -// try -// { -// emit exportProgress(totalCount, exportedNumber / 2); -// -// seriesWriter->Update(); -// -// emit exportProgress(totalCount, exportedNumber); -// } -// catch (itk::ExceptionObject & excp) -// { -// std::cerr << "Exception thrown while writing the series " << std::endl; -// std::cerr << excp << std::endl; -// } -} - -//void DicomExporter::modifyDicomTags(SeriesReaderTypeExport::DictionaryArrayRawPointer dicArray) -//{ -// for (int i = 0; i < (*dicArray).size(); i++) -// { -// itk::MetaDataDictionary *dic = (*dicArray).at(i); -// -// if (exportOptions.windowLevel != -1) -// { -// std::string entryId(TAG_WindowLevel); -// itk::EncapsulateMetaData(*dic, entryId, std::to_string(exportOptions.windowLevel)); -// } -// -// if (exportOptions.windowWidth != -1) -// { -// std::string entryId(TAG_WindowWidth); -// itk::EncapsulateMetaData(*dic, entryId, std::to_string(exportOptions.windowWidth)); -// } -// -// if (exportOptions.isAnonymization) -// { -// itk::EncapsulateMetaData(*dic, TAG_InstitutionName, "anonymized"); -// itk::EncapsulateMetaData(*dic, TAG_InstitutionAddress, "anonymized"); -// itk::EncapsulateMetaData(*dic, TAG_ReferringPhysicianName, "anonymized"); -// itk::EncapsulateMetaData(*dic, TAG_OperatorsName, "anonymized"); -// itk::EncapsulateMetaData(*dic, TAG_PatientAddress, "anonymized"); -// itk::EncapsulateMetaData(*dic, TAG_PatientTelephoneNumbers, "anonymized"); -// itk::EncapsulateMetaData(*dic, TAG_OtherPatientNames, "anonymized"); -// itk::EncapsulateMetaData(*dic, TAG_OtherPatientIDs, "anonymized"); -// itk::EncapsulateMetaData(*dic, TAG_OtherPatientIDsSequence, ""); -// itk::EncapsulateMetaData(*dic, TAG_PatientName, "anonymized"); -// itk::EncapsulateMetaData(*dic, TAG_PatientBirthDate, "19000101"); -// itk::EncapsulateMetaData(*dic, TAG_PatientSex, "NA"); -// itk::EncapsulateMetaData(*dic, TAG_PatientAge, "NA"); -// itk::EncapsulateMetaData(*dic, TAG_PatientID, "anonymized"); -// itk::EncapsulateMetaData(*dic, TAG_AccessionNumber, "anonymized"); -// } -// -// }//for end -//} void DicomExporter::caculateExportTotalCount() { for (int i = 0; i < exportOptions.inputData.size(); i++) { - QString fileName = exportOptions.inputData.at(i); - - QFileInfo fileInfo(fileName); - QDir dir(fileName); - - if (fileInfo.isFile()) - { - totalCount++; - } - else if (dir.exists()) - { - QStringList filter; - QFileInfoList fileList = dir.entryInfoList(filter); - totalCount += fileList.count(); - totalCount -= 2; - } + auto property = exportOptions.inputData.at(i); + totalCount+= property->GetFileNames().size(); } } diff --git a/src/src/Deprecated/Export/dicomexporter.h b/src/src/Deprecated/Export/dicomexporter.h index cd65dad..cd1e59d 100644 --- a/src/src/Deprecated/Export/dicomexporter.h +++ b/src/src/Deprecated/Export/dicomexporter.h @@ -3,12 +3,6 @@ #include #include "exportoptions.h" -//#include -//#include -//#include -//#include -//#include -//#include #include #include #include @@ -24,8 +18,6 @@ #include #include "Rendering/Viewer/DICOMImageViewer.h" -//#include "itkMetaDataObject.h" -//#include "itkMetaDataDictionary.h" class DicomExporter : public QObject @@ -45,79 +37,18 @@ public: signals: void exportFinished(); + void exportError(); void exportProgress(int total, int progress); -public slots: - private: - //dicom tags - const std::string TAG_WindowLevel = "0028|1050"; - const std::string TAG_WindowWidth = "0028|1051"; - - //anonymization - const std::string TAG_InstitutionName = "0008|0080"; - const std::string TAG_InstitutionAddress = "0008|0081"; - const std::string TAG_ReferringPhysicianName = "0008|0090"; - const std::string TAG_OperatorsName = "0008|1070"; - const std::string TAG_PatientAddress = "0010|1040"; - const std::string TAG_PatientTelephoneNumbers = "0010|2154"; - const std::string TAG_OtherPatientNames = "0010|1001"; - const std::string TAG_OtherPatientIDs = "0010|1000"; - const std::string TAG_OtherPatientIDsSequence = "0010|1002"; - const std::string TAG_PatientName = "0010|0010"; - const std::string TAG_PatientBirthDate = "0010|0030"; - const std::string TAG_PatientSex = "0010|0040"; - const std::string TAG_PatientAge = "0010|1010"; - const std::string TAG_PatientID = "0010|0020"; - const std::string TAG_AccessionNumber = "0008|0050"; - - //bmp jpg png tiff exprt releated objects - static const unsigned int InputDimensionExport = 3; - typedef signed short PixelTypeExport; -// typedef itk::Image InputImageTypeExport; -// typedef itk::GDCMImageIO ImageIOTypeExport; -// typedef itk::ImageSeriesReader SeriesReaderTypeExport; -// typedef itk::ImageToVTKImageFilter ConnectorTypeExport; -// typedef itk::GDCMSeriesFileNames InputNamesGeneratorTypeExport; - - //dicom export releated objects - typedef signed short OutputPixelType; - static const unsigned int OutputDimension = 2; -// typedef itk::Image Image2DType; -// typedef itk::ImageSeriesWriter SeriesWriterType; - -private: - void initVTK(); - void initDataReader(); - void loadDicomFileAndRender(int file_type); - //void updateCornerInfo(int slice, int maxslice); - void doExport(int file_type); - QString getFileExtention(); - void writeToFile(const QString& fileName); - void writeToPngFile(vtkSmartPointer windowToImageFilter, const QString& fileName); - void writeToBmpFile(vtkSmartPointer windowToImageFilter, const QString& fileName); - void writeToJpgFile(vtkSmartPointer windowToImageFilter, const QString& fileName); - void writeToTiffFile(vtkSmartPointer windowToImageFilter, const QString& fileName); - void exportPicture(const QString& fileName); - void exportDicom(const QString& fileName); - void exportSingleDicomFile(const QString& fileName); - void exportDicomDirectory(const QString& fileName); -// void modifyDicomTags(SeriesReaderTypeExport::DictionaryArrayRawPointer dicArray); + const char* getFileExtention(); void caculateExportTotalCount(); private: ExportOptions exportOptions; int totalCount;//the total count of image to be exported int exportedNumber;//the exported image index - - //itk vtk releated objects -// ImageIOTypeExport::Pointer m_gdcmIOExport; -// SeriesReaderTypeExport::Pointer m_itkSeriesReaderExport; -// ConnectorTypeExport::Pointer m_itkConnectorExport; -// InputNamesGeneratorTypeExport::Pointer m_inputNamesExport; - vtkSmartPointer m_glrenWinExport; - vtkSmartPointer m_imageViewerExport; }; #endif // DICOMEXPORTER_H \ No newline at end of file diff --git a/src/src/Deprecated/Export/exportoptions.h b/src/src/Deprecated/Export/exportoptions.h index f19d8bc..9a54cff 100644 --- a/src/src/Deprecated/Export/exportoptions.h +++ b/src/src/Deprecated/Export/exportoptions.h @@ -6,14 +6,16 @@ #include class SeriesImageSet; - +class ExtendMedicalImageProperties; class ExportOptions { public: explicit ExportOptions(); - QList inputData;//the fileName or directory list to export + QList inputData; + + int slice = -1l; int windowWidth;//exported window width int windowLevel;//exported window level @@ -41,7 +43,6 @@ public: QSize customPictureSize;//apply when user choose customsize - SeriesImageSet *serie; }; #endif // EXPORTOPTIONS_H \ No newline at end of file diff --git a/src/src/IO/Convert/ConverterBase.cpp b/src/src/IO/Convert/ConverterBase.cpp index e982d48..8fa7283 100644 --- a/src/src/IO/Convert/ConverterBase.cpp +++ b/src/src/IO/Convert/ConverterBase.cpp @@ -6,7 +6,6 @@ #include #include -#include #include #include "IO/DICOM/DICOMPixelDataHelper.h" diff --git a/src/src/IO/Convert/DICOMToQImageConverter.cpp b/src/src/IO/Convert/DICOMToQImageConverter.cpp new file mode 100644 index 0000000..8266d65 --- /dev/null +++ b/src/src/IO/Convert/DICOMToQImageConverter.cpp @@ -0,0 +1,39 @@ +// +// Created by Krad on 2022/9/28. +// + +#include "DICOMToQImageConverter.h" + +#include +#include + +#include "IO/DICOM/DICOMPixelDataHelper.h" + +void DICOMToQImageConverter::save(const char *filename) { + if (! m_DICOMFileName.empty()) { + void* data = nullptr; + int size[2] = {0, 0}; + if (m_Frame < 0) { + DICOMPixelDataHelper::GetRenderedBuffer(m_DICOMFileName.c_str(), + data,size, m_Sample, m_Window[0], m_Window[1]); + } else { + DICOMPixelDataHelper::GetMultiFrameRenderedBuffer(m_DICOMFileName.c_str(), + data,size, m_Sample,m_Frame, m_Window[0], m_Window[1]); + } + if(data){ + m_Image = new QImage((uchar*)data,size[0],size[1],QImage::Format_RGB888); + } + } +} + +QImage *DICOMToQImageConverter::getQImage() { + return m_Image; +} + +DICOMToQImageConverter::DICOMToQImageConverter():ConverterBase() { + +} + +DICOMToQImageConverter::~DICOMToQImageConverter() { + +} diff --git a/src/src/IO/Convert/DICOMToQImageConverter.h b/src/src/IO/Convert/DICOMToQImageConverter.h new file mode 100644 index 0000000..c43d2f0 --- /dev/null +++ b/src/src/IO/Convert/DICOMToQImageConverter.h @@ -0,0 +1,27 @@ +// +// Created by Krad on 2022/9/28. +// + +#ifndef OMEGAV_DICOMTOQIMAGECONVERTER_H +#define OMEGAV_DICOMTOQIMAGECONVERTER_H +#include "ConverterBase.h" +class QImage; +class DICOMToQImageConverter:public ConverterBase { +public: + DICOMToQImageConverter(); + + ~DICOMToQImageConverter() override ; + + /** + * 保存函数 + * @param filename 输出的绝对路径 + */ + void save(const char *filename = nullptr) override; + QImage* getQImage(); + +private: + QImage* m_Image = nullptr; +}; + + +#endif //OMEGAV_DICOMTOQIMAGECONVERTER_H diff --git a/src/src/IO/DICOM/DICOMPixelDataHelper.cpp b/src/src/IO/DICOM/DICOMPixelDataHelper.cpp index c24d56e..35a31ba 100644 --- a/src/src/IO/DICOM/DICOMPixelDataHelper.cpp +++ b/src/src/IO/DICOM/DICOMPixelDataHelper.cpp @@ -263,6 +263,67 @@ bool DICOMPixelDataHelper::GetRenderedData(const char *path, vtkImageData *data, return false; } +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); + } + else{ + return false; + } + } + DicomImage dcmImage(fileFormat, fileFormat->getDataset()->getOriginalXfer(), CIF_UsePartialAccessToPixelData, + frame, 1); + if (dcmImage.getStatus() == EIS_Normal) { + RenderToImageData(data, sample, windowLevel, windowWidth, dcmImage); + return true; + } + return false; + +} + + +bool DICOMPixelDataHelper::GetRenderedBuffer(const char *path, void *&buffer, int*size, int sample, double windowLevel, + double windowWidth) { + DcmFileFormat fileFormat; + if (fileFormat.loadFile(path).good()) { + DcmDataset *dset = fileFormat.getDataset(); + DicomImage dcmImage(&fileFormat, dset->getOriginalXfer(), CIF_MayDetachPixelData); + size[0] =dcmImage.getWidth(); + size[1] =dcmImage.getHeight(); + RenderToBuffer(buffer, sample, windowLevel, windowWidth, dcmImage); + return true; + } + return false; +} + +bool DICOMPixelDataHelper::GetMultiFrameRenderedBuffer(const char *path, void *&buffer,int*size, 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); + } + else{ + return false; + } + } + auto dataset = fileFormat->getDataset(); + DicomImage dcmImage(dataset, dataset->getOriginalXfer(), CIF_UsePartialAccessToPixelData, + frame, 1); + if (dcmImage.getStatus() == EIS_Normal) { + size[0] =dcmImage.getWidth(); + size[1] =dcmImage.getHeight(); + RenderToBuffer(buffer, 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); @@ -275,23 +336,12 @@ void DICOMPixelDataHelper::RenderToImageData(vtkImageData *data, int sample, dou 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; - } - } +void DICOMPixelDataHelper::RenderToBuffer(void *&data, int sample, double windowLevel, double windowWidth, + DicomImage &dcmImage) { + if (sample == 1){ + dcmImage.setWindow(windowLevel, windowWidth); } - delete fileFormat; - return false; - + long length = dcmImage.getWidth()*dcmImage.getHeight()*3; + data = new uchar[length]; + dcmImage.createWindowsDIB(data,length); } diff --git a/src/src/IO/DICOM/DICOMPixelDataHelper.h b/src/src/IO/DICOM/DICOMPixelDataHelper.h index bf7fffe..eff8247 100644 --- a/src/src/IO/DICOM/DICOMPixelDataHelper.h +++ b/src/src/IO/DICOM/DICOMPixelDataHelper.h @@ -44,6 +44,8 @@ public: */ static bool GetRenderedData(const char * path, vtkImageData* data, int sample, double windowLevel, double windowWidth); + static bool GetRenderedBuffer(const char * path, void*& buffer,int* size, int sample, double windowLevel, double windowWidth); + /** * 从Multi-frame类型的DICOM文件中,获取已渲染图像 * 至vtkImageData中,主要用于DICOM数据的导出, @@ -58,6 +60,8 @@ public: * @return */ static bool GetMultiFrameRenderedData(const char * path, vtkImageData* data, int sample,int frame, double windowLevel, double windowWidth); + + static bool GetMultiFrameRenderedBuffer(const char * path, void*& data,int* size, int sample,int frame, double windowLevel, double windowWidth); /** * Get Pixel Data with Rescaled, result is calculate as integer, and arrange as integer. * @@ -172,6 +176,9 @@ public: */ static void RenderToImageData(vtkImageData *data, int sample, double windowLevel, double windowWidth, DicomImage &dcmImage); + + static void + RenderToBuffer(void *&data, int sample, double windowLevel, double windowWidth, DicomImage &dcmImage); }; diff --git a/src/src/UI/Dialog/exportdialog.cpp b/src/src/UI/Dialog/exportdialog.cpp index de38154..510baa4 100644 --- a/src/src/UI/Dialog/exportdialog.cpp +++ b/src/src/UI/Dialog/exportdialog.cpp @@ -1,12 +1,20 @@ #include "exportdialog.h" #include "ui_exportdialog.h" +#include + +#include "UI/Manager/ImageViewManager.h" +#include "Deprecated/Export/dicomexporterthread.h" + ExportDialog::ExportDialog(QWidget *parent) : QDialog(parent), - ui(new Ui::ExportDialog) + ui(new Ui::ExportDialog), + worker(nullptr) { ui->setupUi(this); ui->progressBar->setVisible(false); + ui->rbDICOM->setVisible(false); + ui->rbTIFF->setVisible(false); init(); } @@ -63,33 +71,28 @@ void ExportDialog::onBtnExportClicked() //export files if (ui->rbCurrentImage->isChecked())//current image { - if (cur_view->hasSeries()) + if (m_Manager->getCurrentView()->hasSeries()) { - QString imageName(cur_view->getSeriesInstance()->getCurImageName()); - options.inputData.push_back(imageName); + auto property = m_Manager->getCurrentView()->getSeriesInstance()->GetProperty(); + options.inputData.push_back(property); + options.slice = m_Manager->getCurrentView()->getSlice(); } } else if (ui->rbCurrentSeries->isChecked())//current series { - if (cur_view->hasSeries()) + if (m_Manager->getCurrentView()->hasSeries()) { - QString serieName(cur_view->getSeriesInstance()->getSeriesName()); - options.inputData.push_back(serieName); + auto property = m_Manager->getCurrentView()->getSeriesInstance()->GetProperty(); + options.inputData.push_back(property); } } else if (ui->rbAllOpendSeries->isChecked())// all opened series { - //disable this function -// InstancesVecType instanceVec; -// DicomLoader::GetInstance()->getOpenedInstancesVec(instanceVec); -// for (int i = 0; i < instanceVec.size(); i++) -// { -// SeriesImageSet *instance = instanceVec.at(i); -// if (instance != nullptr) -// { -// options.inputData.push_back(instance->getSeriesName()); -// } -// } + for(auto view:m_Manager->getViewList()){ + if (view->hasSeries()){ + options.inputData.push_back(view->getSeriesInstance()->GetProperty()); + } + } } if (ui->rbJPEG->isChecked()) @@ -139,10 +142,10 @@ void ExportDialog::onBtnExportClicked() options.isAnonymization = false; } - options.windowLevel = cur_view->getImageViewer()->GetColorLevel(); - options.windowWidth = cur_view->getImageViewer()->GetColorWindow(); - options.serie = cur_view->getSeriesInstance(); - DicomExporterThread *worker = new DicomExporterThread(options); + options.windowLevel = m_Manager->getCurrentView()->getImageViewer()->GetColorLevel(); + options.windowWidth = m_Manager->getCurrentView()->getImageViewer()->GetColorWindow(); + + worker = new DicomExporterThread(options); //disconnect(worker, SIGNAL(exportProgress(int, int)), this, SLOT(onExportProgress(int, int))); connect(worker, SIGNAL(exportProgress(int, int)), this, SLOT(onExportProgress(int, int))); @@ -169,14 +172,13 @@ void ExportDialog::onExportFinished() { ui->progressBar->setVisible(false); ui->btnExport->setEnabled(true); + if (ui->cbShowAfterExport->isChecked()){ + QDesktopServices::openUrl(QUrl(QString("file:///%1").arg(ui->edtExportFolder->text()))); + } } -void ExportDialog::setCurView(DicomImageView *view) +void ExportDialog::setViewManager(ImageViewManager *manager) { - cur_view = view; + m_Manager = manager; } -//void ExportDialog::setViewContainer(ViewContainerWidget *widget) -//{ -// viewContainerWidget = widget; -//} diff --git a/src/src/UI/Dialog/exportdialog.h b/src/src/UI/Dialog/exportdialog.h index 380f4c7..b1c8179 100644 --- a/src/src/UI/Dialog/exportdialog.h +++ b/src/src/UI/Dialog/exportdialog.h @@ -4,13 +4,12 @@ #include #include "Deprecated/Export/exportoptions.h" #include "qdir.h" -#include "Deprecated/Export/dicomexporterthread.h" #include "QFileDialog" #include "IO/DICOM/DicomLoader.h" #include "UI/Widget/ImageView/dicomimageview.h" - - +class DicomExporterThread; +class ImageViewManager; namespace Ui { class ExportDialog; @@ -24,7 +23,7 @@ public: explicit ExportDialog(QWidget *parent = nullptr); ~ExportDialog(); //void setViewContainer(ViewContainerWidget *widget) - void setCurView(DicomImageView *view); + void setViewManager(ImageViewManager *manager); public slots: void onBtnExportClicked(); @@ -40,7 +39,8 @@ private: private: Ui::ExportDialog *ui; //ViewContainerWidget *viewContainerWidget; - DicomImageView *cur_view; + ImageViewManager *m_Manager; + DicomExporterThread *worker; }; #endif // EXPORTDIALOG_H diff --git a/src/src/UI/Dialog/exportdialog.ui b/src/src/UI/Dialog/exportdialog.ui index 35897e8..3f469ce 100644 --- a/src/src/UI/Dialog/exportdialog.ui +++ b/src/src/UI/Dialog/exportdialog.ui @@ -135,36 +135,9 @@ Export Location - - - - Export Folder - - - - - - - Qt::NoFocus - - - Choose Folder... - - - - - - - FileName Prefix - - - - - - @@ -178,6 +151,40 @@ + + + + Export Folder + + + + + + + FileName Prefix + + + + + + + + + + Qt::NoFocus + + + Choose Folder... + + + + + + + Show in Explorer after exported + + + @@ -287,8 +294,8 @@ - + diff --git a/src/src/UI/Widget/ImageView/dicomimageview.cpp b/src/src/UI/Widget/ImageView/dicomimageview.cpp index 24e35f5..722cac4 100644 --- a/src/src/UI/Widget/ImageView/dicomimageview.cpp +++ b/src/src/UI/Widget/ImageView/dicomimageview.cpp @@ -495,6 +495,9 @@ void DicomImageView::setSlice(int slice) { mImageViewer->SetSlice(slice); } } +int DicomImageView::getSlice(){ + return mImageViewer->GetSlice(); +} void DicomImageView::addSlice(int step) { if (mImageViewer == nullptr) { diff --git a/src/src/UI/Widget/ImageView/dicomimageview.h b/src/src/UI/Widget/ImageView/dicomimageview.h index a2cb3d0..2c0fc0e 100644 --- a/src/src/UI/Widget/ImageView/dicomimageview.h +++ b/src/src/UI/Widget/ImageView/dicomimageview.h @@ -113,6 +113,9 @@ public: void setSlice(int slice); + int getSlice(); + + //Sync zoom void setZoomScale(double scale); diff --git a/src/src/UI/Window/QDicomViewer.cpp b/src/src/UI/Window/QDicomViewer.cpp index 06b5a7b..998e6e9 100644 --- a/src/src/UI/Window/QDicomViewer.cpp +++ b/src/src/UI/Window/QDicomViewer.cpp @@ -219,7 +219,7 @@ void QDicomViewer::initGeneralTool() { connect(ui->toolBar, &DefaultToolBar::save, this, [=] { if (nullptr == exportDialog) { exportDialog = new ExportDialog(this); - exportDialog->setCurView(ui->viewContainer->getCurrentView()); + exportDialog->setViewManager(ui->viewContainer->getViewManager()); exportDialog->setModal(false); } exportDialog->show();