Export with annotation.
This commit is contained in:
65
src/src/Deprecated/Export/AnnotationAppender.cpp
Normal file
65
src/src/Deprecated/Export/AnnotationAppender.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// Created by Krad on 2022/9/29.
|
||||
//
|
||||
|
||||
#include "AnnotationAppender.h"
|
||||
|
||||
#include <QImage>
|
||||
#include <QPixmap>
|
||||
#include <QPainter>
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
46
src/src/Deprecated/Export/AnnotationAppender.h
Normal file
46
src/src/Deprecated/Export/AnnotationAppender.h
Normal file
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// Created by Krad on 2022/9/29.
|
||||
//
|
||||
|
||||
#ifndef OMEGAV_ANNOTATIONAPPENDER_H
|
||||
#define OMEGAV_ANNOTATIONAPPENDER_H
|
||||
|
||||
#include <QString>
|
||||
#include <vector>
|
||||
|
||||
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<QString> m_TopLeftText;
|
||||
std::vector<QString> m_TopRightText;
|
||||
std::vector<QString> m_BottomLeftText;
|
||||
std::vector<QString> m_BottomRightText;
|
||||
};
|
||||
|
||||
|
||||
#endif //OMEGAV_ANNOTATIONAPPENDER_H
|
||||
@@ -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];
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ public:
|
||||
signals:
|
||||
void exportFinished();
|
||||
void exportProgress(int total, int progress);
|
||||
void exportError(QString msg);
|
||||
|
||||
public slots:
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "ui_exportdialog.h"
|
||||
|
||||
#include <QDesktopServices>
|
||||
#include <QMessageBox>
|
||||
|
||||
#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();
|
||||
|
||||
Reference in New Issue
Block a user