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/DICOM/DICOMPixelDataHelper.h"
|
||||||
#include "IO/Convert/DICOMToQImageConverter.h"
|
#include "IO/Convert/DICOMToQImageConverter.h"
|
||||||
|
#include "AnnotationAppender.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const char* FileExtention[3]={
|
const char* FileExtention[3]={
|
||||||
@@ -36,23 +37,16 @@ void DicomExporter::execute(ExportOptions options)
|
|||||||
if (exportOptions.slice >= 0){
|
if (exportOptions.slice >= 0){
|
||||||
if (exportOptions.inputData.empty()
|
if (exportOptions.inputData.empty()
|
||||||
|| exportOptions.inputData[0]->GetFileNames().empty()) {
|
|| exportOptions.inputData[0]->GetFileNames().empty()) {
|
||||||
emit exportError();
|
emit exportError("No image selected!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::string fileName = exportOptions.inputData[0]->GetFileNames()[exportOptions.slice].first;
|
QImage *img = getConvertedImage(exportOptions.inputData[0],
|
||||||
long frame = exportOptions.inputData[0]->GetFileNames()[exportOptions.slice].second;
|
exportOptions.slice,exportOptions.windowLevel,exportOptions.windowWidth);
|
||||||
DICOMToQImageConverter convert;
|
auto property = exportOptions.inputData[0];
|
||||||
if (frame>=0){
|
double window[2] = { (double)exportOptions.windowWidth,(double)exportOptions.windowLevel};
|
||||||
convert.setFrame(frame);
|
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")
|
bool ret = img->save(QString("%1/%2%3.%4")
|
||||||
.arg(exportOptions.exportDirectory,exportOptions.fileNamePrefix)
|
.arg(exportOptions.exportDirectory,exportOptions.fileNamePrefix)
|
||||||
.arg(0).arg(getFileExtention()),getFileExtention());
|
.arg(0).arg(getFileExtention()),getFileExtention());
|
||||||
@@ -61,7 +55,7 @@ void DicomExporter::execute(ExportOptions options)
|
|||||||
emit exportFinished();
|
emit exportFinished();
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
emit exportError();
|
emit exportError("Save to disk failed!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,21 +69,12 @@ void DicomExporter::execute(ExportOptions options)
|
|||||||
QString savedir = QString("%1/%2").arg(exportOptions.exportDirectory,property->GetSeriesUID());
|
QString savedir = QString("%1/%2").arg(exportOptions.exportDirectory,property->GetSeriesUID());
|
||||||
dir.mkpath(savedir);
|
dir.mkpath(savedir);
|
||||||
for (int j = 0; j < property->GetFileNames().size(); ++j) {
|
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);
|
double * window = property->GetNthWindowLevelPreset(0);
|
||||||
convert.setWindow(window[1], window[0]);
|
QImage *img = getConvertedImage(exportOptions.inputData[i],
|
||||||
if (property->GetSamplePerPixel()>1)
|
j,window[1],window[0]);
|
||||||
{
|
if (exportOptions.cornerAnnotation != ExportOptions::Disabled) {
|
||||||
convert.setColorImage(property->GetSamplePerPixel());
|
appendAnnotation(property, j, window, img);
|
||||||
}
|
}
|
||||||
convert.save();
|
|
||||||
auto img = convert.getQImage();
|
|
||||||
bool ret = img->save(QString("%1/%2%3.%4")
|
bool ret = img->save(QString("%1/%2%3.%4")
|
||||||
.arg(savedir,exportOptions.fileNamePrefix)
|
.arg(savedir,exportOptions.fileNamePrefix)
|
||||||
.arg(j).arg(getFileExtention()),getFileExtention());
|
.arg(j).arg(getFileExtention()),getFileExtention());
|
||||||
@@ -106,13 +91,79 @@ void DicomExporter::execute(ExportOptions options)
|
|||||||
emit exportFinished();
|
emit exportFinished();
|
||||||
}
|
}
|
||||||
else{
|
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()
|
const char * DicomExporter::getFileExtention()
|
||||||
{
|
{
|
||||||
return FileExtention[exportOptions.exportFileFormat];
|
return FileExtention[exportOptions.exportFileFormat];
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void exportFinished();
|
void exportFinished();
|
||||||
void exportError();
|
void exportError(QString msg);
|
||||||
void exportProgress(int total, int progress);
|
void exportProgress(int total, int progress);
|
||||||
|
|
||||||
|
|
||||||
@@ -49,6 +49,9 @@ private:
|
|||||||
ExportOptions exportOptions;
|
ExportOptions exportOptions;
|
||||||
int totalCount;//the total count of image to be exported
|
int totalCount;//the total count of image to be exported
|
||||||
int exportedNumber;//the exported image index
|
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
|
#endif // DICOMEXPORTER_H
|
||||||
@@ -17,6 +17,7 @@ void DicomExporterThread::run()
|
|||||||
exporter = new DicomExporter();
|
exporter = new DicomExporter();
|
||||||
connect(exporter, SIGNAL(exportProgress(int, int)), this, SIGNAL(exportProgress(int, int)));
|
connect(exporter, SIGNAL(exportProgress(int, int)), this, SIGNAL(exportProgress(int, int)));
|
||||||
connect(exporter, SIGNAL(exportFinished()), this, SIGNAL(exportFinished()));
|
connect(exporter, SIGNAL(exportFinished()), this, SIGNAL(exportFinished()));
|
||||||
|
connect(exporter, &DicomExporter::exportError, this, &DicomExporterThread::exportError);
|
||||||
|
|
||||||
exporter->execute(exportOptions);
|
exporter->execute(exportOptions);
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ public:
|
|||||||
signals:
|
signals:
|
||||||
void exportFinished();
|
void exportFinished();
|
||||||
void exportProgress(int total, int progress);
|
void exportProgress(int total, int progress);
|
||||||
|
void exportError(QString msg);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "ui_exportdialog.h"
|
#include "ui_exportdialog.h"
|
||||||
|
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
#include "UI/Manager/ImageViewManager.h"
|
#include "UI/Manager/ImageViewManager.h"
|
||||||
#include "Deprecated/Export/dicomexporterthread.h"
|
#include "Deprecated/Export/dicomexporterthread.h"
|
||||||
@@ -146,11 +147,12 @@ void ExportDialog::onBtnExportClicked()
|
|||||||
options.windowWidth = m_Manager->getCurrentView()->getImageViewer()->GetColorWindow();
|
options.windowWidth = m_Manager->getCurrentView()->getImageViewer()->GetColorWindow();
|
||||||
|
|
||||||
worker = new DicomExporterThread(options);
|
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)));
|
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, SIGNAL(exportFinished()), this, SLOT(onExportFinished()));
|
||||||
|
connect(worker, &DicomExporterThread::exportError, [=](QString msg){
|
||||||
|
QMessageBox::warning(this,"Export error!",msg);
|
||||||
|
});
|
||||||
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
|
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
|
||||||
|
|
||||||
worker->start();
|
worker->start();
|
||||||
|
|||||||
Reference in New Issue
Block a user