From f575691a60edc6c4495bcf1c28ed7a0d13d92e23 Mon Sep 17 00:00:00 2001 From: Krad Date: Sun, 9 Oct 2022 09:22:05 +0800 Subject: [PATCH] Export with annotation. --- .../Deprecated/Export/AnnotationAppender.cpp | 65 +++++++++++ .../Deprecated/Export/AnnotationAppender.h | 46 ++++++++ src/src/Deprecated/Export/dicomexporter.cpp | 109 +++++++++++++----- src/src/Deprecated/Export/dicomexporter.h | 5 +- .../Deprecated/Export/dicomexporterthread.cpp | 1 + .../Deprecated/Export/dicomexporterthread.h | 1 + src/src/UI/Dialog/exportdialog.cpp | 6 +- 7 files changed, 201 insertions(+), 32 deletions(-) create mode 100644 src/src/Deprecated/Export/AnnotationAppender.cpp create mode 100644 src/src/Deprecated/Export/AnnotationAppender.h diff --git a/src/src/Deprecated/Export/AnnotationAppender.cpp b/src/src/Deprecated/Export/AnnotationAppender.cpp new file mode 100644 index 0000000..4763fe5 --- /dev/null +++ b/src/src/Deprecated/Export/AnnotationAppender.cpp @@ -0,0 +1,65 @@ +// +// Created by Krad on 2022/9/29. +// + +#include "AnnotationAppender.h" + +#include +#include +#include + + +void AnnotationAppender::append() { + QPixmap pic = QPixmap::fromImage(*m_Image); + QPainter painter(&pic); + QPen pen; + QFont font("Futura"); + font.setPixelSize(m_FontSize); + painter.setFont(font); + pen.setColor(QColor(255, 255, 0)); + painter.setPen(pen); + //TopLeft + for (int i = 0; i < m_TopLeftText.size(); ++i) { + painter.drawText(m_Margin,m_Margin+i*m_Spacing+m_FontSize*(i+1),m_TopLeftText[i]); + } + //TopRight + for (int i = 0; i < m_TopRightText.size(); ++i) { + int textLength = m_TopRightText[i].size(); + painter.drawText(pic.width()-m_Margin-textLength*m_FontSize/2, + m_Margin+i*m_Spacing+m_FontSize*(i+1),m_TopRightText[i]); + } + //BottomLeft + for (int i = 0; i < m_BottomLeftText.size(); ++i) { + painter.drawText(m_Margin, + pic.height()-m_Margin-i*m_Spacing - m_FontSize * i, + m_BottomLeftText[i]); + } + //BottomRight + for (int i = 0; i < m_BottomRightText.size(); ++i) { + int textLength = m_BottomRightText[i].size(); + painter.drawText(pic.width()-m_Margin-textLength*m_FontSize/2, + pic.height()-m_Margin-i*m_Spacing-m_FontSize*i,m_BottomRightText[i]); + } + *m_Image = pic.toImage(); +} + +void AnnotationAppender::addAnnotationText(AnnotationAppender::AnnotationPosition position, QString text) { + switch (position){ + case TopLeft: + m_TopLeftText.push_back(text); + break; + case TopRight: + m_TopRightText.push_back(text); + break; + case BottomLeft: + m_BottomLeftText.push_back(text); + break; + case BottomRight: + m_BottomRightText.push_back(text); + break; + } +} + +AnnotationAppender::AnnotationAppender(QImage *img) { + m_Image = img; +} diff --git a/src/src/Deprecated/Export/AnnotationAppender.h b/src/src/Deprecated/Export/AnnotationAppender.h new file mode 100644 index 0000000..a6213e7 --- /dev/null +++ b/src/src/Deprecated/Export/AnnotationAppender.h @@ -0,0 +1,46 @@ +// +// Created by Krad on 2022/9/29. +// + +#ifndef OMEGAV_ANNOTATIONAPPENDER_H +#define OMEGAV_ANNOTATIONAPPENDER_H + +#include +#include + +class QImage; +class AnnotationAppender { + +public: + AnnotationAppender(QImage* img); + enum AnnotationPosition{ + TopLeft, + TopRight, + BottomLeft, + BottomRight + }; + void setMargin(int margin){ + m_Margin = margin; + } + void setSpacing(int spacing){ + m_Spacing = spacing; + } + void setFontSize(int size){ + m_FontSize = size; + } + void addAnnotationText(AnnotationPosition position, QString text); + void append(); + +private: + QImage* m_Image; + int m_Margin = 5; + int m_Spacing = 3; + int m_FontSize = 16; + std::vector m_TopLeftText; + std::vector m_TopRightText; + std::vector m_BottomLeftText; + std::vector m_BottomRightText; +}; + + +#endif //OMEGAV_ANNOTATIONAPPENDER_H diff --git a/src/src/Deprecated/Export/dicomexporter.cpp b/src/src/Deprecated/Export/dicomexporter.cpp index 935104e..ea775f7 100644 --- a/src/src/Deprecated/Export/dicomexporter.cpp +++ b/src/src/Deprecated/Export/dicomexporter.cpp @@ -5,6 +5,7 @@ #include "IO/DICOM/DICOMPixelDataHelper.h" #include "IO/Convert/DICOMToQImageConverter.h" +#include "AnnotationAppender.h" namespace { const char* FileExtention[3]={ @@ -36,23 +37,16 @@ void DicomExporter::execute(ExportOptions options) if (exportOptions.slice >= 0){ if (exportOptions.inputData.empty() || exportOptions.inputData[0]->GetFileNames().empty()) { - emit exportError(); + emit exportError("No image selected!"); 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); + QImage *img = getConvertedImage(exportOptions.inputData[0], + exportOptions.slice,exportOptions.windowLevel,exportOptions.windowWidth); + auto property = exportOptions.inputData[0]; + double window[2] = { (double)exportOptions.windowWidth,(double)exportOptions.windowLevel}; + if (exportOptions.cornerAnnotation != ExportOptions::Disabled){ + appendAnnotation(exportOptions.inputData[0],exportOptions.slice,window,img); } - 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()); @@ -61,7 +55,7 @@ void DicomExporter::execute(ExportOptions options) emit exportFinished(); } else{ - emit exportError(); + emit exportError("Save to disk failed!"); return; } } @@ -75,21 +69,12 @@ void DicomExporter::execute(ExportOptions options) 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()); + QImage *img = getConvertedImage(exportOptions.inputData[i], + j,window[1],window[0]); + if (exportOptions.cornerAnnotation != ExportOptions::Disabled) { + appendAnnotation(property, j, window, img); } - convert.save(); - auto img = convert.getQImage(); bool ret = img->save(QString("%1/%2%3.%4") .arg(savedir,exportOptions.fileNamePrefix) .arg(j).arg(getFileExtention()),getFileExtention()); @@ -106,13 +91,79 @@ void DicomExporter::execute(ExportOptions options) emit exportFinished(); } else{ - emit exportError(); + emit exportError(QString("Total %1 processed, %2 succeed!").arg(totalCount).arg(successCount)); } } } +QImage *DicomExporter::getConvertedImage(ExtendMedicalImageProperties* property,int slice,int wl, int ww) { + string fileName = property->GetFileNames()[slice].first; + long frame = property->GetFileNames()[slice].second; + DICOMToQImageConverter convert; + if (frame>=0){ + convert.setFrame(frame); + } + convert.setInputDICOMFile(fileName.c_str()); + convert.setWindow(wl, ww); + if (property->GetSamplePerPixel() > 1) + { + convert.setColorImage(property->GetSamplePerPixel()); + } + convert.save(); + auto img = convert.getQImage(); + return img; +} + +void DicomExporter::appendAnnotation(ExtendMedicalImageProperties *property, int imageNumber, const double *window, QImage *img) { + AnnotationAppender appender(img); + appender.addAnnotationText(AnnotationAppender::TopLeft, + QString("Im: %1/%2").arg(imageNumber+1) + .arg(property->GetFileNames().size())); + appender.addAnnotationText(AnnotationAppender::TopLeft, + QString("Se:%1").arg(property->GetSeriesNumber())); + bool anonymous = exportOptions.cornerAnnotation==ExportOptions::Basic; + appender.addAnnotationText(AnnotationAppender::TopRight, + !anonymous?property->GetPatientName():"***"); + appender.addAnnotationText(AnnotationAppender::TopRight, + !anonymous?property->GetPatientID():"***"); + QString date = property->GetPatientBirthDate()? + QString("%1/%2/%3") + .arg(property->GetPatientBirthDateYear()) + .arg(property->GetPatientBirthDateMonth()) + .arg(property->GetPatientBirthDateDay()):""; + appender.addAnnotationText(AnnotationAppender::TopRight, + QString("%1 %2").arg(date,property->GetPatientSex()) + ); + appender.addAnnotationText(AnnotationAppender::TopRight, + !anonymous?property->GetInstitutionName():""); + appender.addAnnotationText(AnnotationAppender::TopRight, + property->GetStudyID()); + appender.addAnnotationText(AnnotationAppender::TopRight, + property->GetStudyDescription()); + appender.addAnnotationText(AnnotationAppender::TopRight, + property->GetSeriesDescription()); + if (property->GetSamplePerPixel()==1){ + appender.addAnnotationText(AnnotationAppender::BottomLeft, + QString("WL:%1 WW:%2").arg(window[1]) + .arg(window[0])); + } + QString date2 = property->GetAcquisitionDate()? + QString("%1/%2/%3") + .arg(property->GetAcquisitionDateYear()) + .arg(property->GetAcquisitionDateMonth()) + .arg(property->GetAcquisitionDateDay()):""; + QString time = property->GetAcquisitionTime(); + time = time.length()<6?"": + QString("%1:%2:%3").arg(time.left(2), + time.mid(2,2), time.mid(4,2)); + appender.addAnnotationText(AnnotationAppender::BottomRight, + QString("%1 %2").arg(date2) + .arg(time)); + appender.append(); +} + const char * DicomExporter::getFileExtention() { return FileExtention[exportOptions.exportFileFormat]; diff --git a/src/src/Deprecated/Export/dicomexporter.h b/src/src/Deprecated/Export/dicomexporter.h index cd1e59d..3efb0cf 100644 --- a/src/src/Deprecated/Export/dicomexporter.h +++ b/src/src/Deprecated/Export/dicomexporter.h @@ -37,7 +37,7 @@ public: signals: void exportFinished(); - void exportError(); + void exportError(QString msg); void exportProgress(int total, int progress); @@ -49,6 +49,9 @@ private: ExportOptions exportOptions; int totalCount;//the total count of image to be exported int exportedNumber;//the exported image index + void appendAnnotation(ExtendMedicalImageProperties *property, int imageNumber, const double *window, QImage *img); + + QImage *getConvertedImage(ExtendMedicalImageProperties* property,int slice,int wl, int ww); }; #endif // DICOMEXPORTER_H \ No newline at end of file diff --git a/src/src/Deprecated/Export/dicomexporterthread.cpp b/src/src/Deprecated/Export/dicomexporterthread.cpp index 72897b9..0ff44ab 100644 --- a/src/src/Deprecated/Export/dicomexporterthread.cpp +++ b/src/src/Deprecated/Export/dicomexporterthread.cpp @@ -17,6 +17,7 @@ void DicomExporterThread::run() exporter = new DicomExporter(); connect(exporter, SIGNAL(exportProgress(int, int)), this, SIGNAL(exportProgress(int, int))); connect(exporter, SIGNAL(exportFinished()), this, SIGNAL(exportFinished())); + connect(exporter, &DicomExporter::exportError, this, &DicomExporterThread::exportError); exporter->execute(exportOptions); diff --git a/src/src/Deprecated/Export/dicomexporterthread.h b/src/src/Deprecated/Export/dicomexporterthread.h index f189fa2..2cdcb1f 100644 --- a/src/src/Deprecated/Export/dicomexporterthread.h +++ b/src/src/Deprecated/Export/dicomexporterthread.h @@ -15,6 +15,7 @@ public: signals: void exportFinished(); void exportProgress(int total, int progress); + void exportError(QString msg); public slots: diff --git a/src/src/UI/Dialog/exportdialog.cpp b/src/src/UI/Dialog/exportdialog.cpp index 510baa4..93ebb85 100644 --- a/src/src/UI/Dialog/exportdialog.cpp +++ b/src/src/UI/Dialog/exportdialog.cpp @@ -2,6 +2,7 @@ #include "ui_exportdialog.h" #include +#include #include "UI/Manager/ImageViewManager.h" #include "Deprecated/Export/dicomexporterthread.h" @@ -146,11 +147,12 @@ void ExportDialog::onBtnExportClicked() 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))); - //disconnect(worker, SIGNAL(exportFinished()), this, SLOT(onExportFinished())); connect(worker, SIGNAL(exportFinished()), this, SLOT(onExportFinished())); + connect(worker, &DicomExporterThread::exportError, [=](QString msg){ + QMessageBox::warning(this,"Export error!",msg); + }); connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater())); worker->start();