Separate dataloader module to DIDKit.
This commit is contained in:
@@ -64,6 +64,7 @@ if(DCMTK_LIBRARIES)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory(thirdparty)
|
add_subdirectory(thirdparty)
|
||||||
|
add_subdirectory(DIDKit)
|
||||||
|
|
||||||
|
|
||||||
include_directories(${DCM_NETWORK_INCLUDE_DIRS})
|
include_directories(${DCM_NETWORK_INCLUDE_DIRS})
|
||||||
@@ -72,4 +73,3 @@ add_dependencies(${PROJECT_NAME} dcm_network)
|
|||||||
|
|
||||||
set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE")
|
set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE")
|
||||||
set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
|
set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
|
||||||
#set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS_RELEASE "/level='requireAdministrator' /uiAccess='false'")
|
|
||||||
|
|||||||
27
DIDKit/CMakeLists.txt
Normal file
27
DIDKit/CMakeLists.txt
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
project(DIDKit)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE DIDKit_headers ../src/src/IO/*.h)
|
||||||
|
file(GLOB_RECURSE DIDKit_cpps ../src/src/IO/*.cpp)
|
||||||
|
set(BUILD_SHARED_LIBS ON)
|
||||||
|
if (${BUILD_SHARED_LIBS})
|
||||||
|
include_directories(Defines/)
|
||||||
|
endif()
|
||||||
|
include_directories(../src/src/)
|
||||||
|
|
||||||
|
add_library(DIDKit SHARED ${DIDKit_headers} ${DIDKit_cpps})
|
||||||
|
|
||||||
|
find_package(DCMTK REQUIRED)
|
||||||
|
include_directories(${DCMTK_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(DIDKit ${DCMTK_LIBRARIES})
|
||||||
|
include_directories(${DCM_NETWORK_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
find_package(VTK REQUIRED)
|
||||||
|
include(${VTK_USE_FILE})
|
||||||
|
target_link_libraries(DIDKit ${VTK_LIBRARIES})
|
||||||
|
|
||||||
|
#add_subdirectory(dcm_network)
|
||||||
|
#include_directories(dcm_network)
|
||||||
|
|
||||||
|
include_directories(${DCM_NETWORK_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(DIDKit dcm_network)
|
||||||
|
add_dependencies(DIDKit dcm_network)
|
||||||
71
src/src/Common/Helper/OrientationHelper.cpp
Normal file
71
src/src/Common/Helper/OrientationHelper.cpp
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
//
|
||||||
|
// Created by Krad on 2022/9/20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "OrientationHelper.h"
|
||||||
|
|
||||||
|
#define ORIEN_NUM 4
|
||||||
|
#define SINGLE_INSTANCE 1
|
||||||
|
OrientationMapType OrientationHelper::orien_map;
|
||||||
|
|
||||||
|
std::string OrientationHelper::StringFilter(char* str)
|
||||||
|
{
|
||||||
|
const char s[] = "\\ ";
|
||||||
|
char *token;
|
||||||
|
char *buftmp;
|
||||||
|
token = strtok_s(str, s, &buftmp);
|
||||||
|
std::string trim ="";
|
||||||
|
while (token != NULL) {
|
||||||
|
//printf("%s\n", token);
|
||||||
|
trim += token;
|
||||||
|
token = strtok_s(NULL, s, &buftmp);
|
||||||
|
}
|
||||||
|
return trim;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OrientationHelper::init()
|
||||||
|
{
|
||||||
|
const std::string index[] = { "LH","LF","RH","RF" };
|
||||||
|
std::vector<std::string> indexList(std::begin(index), std::end(index));
|
||||||
|
|
||||||
|
const std::string lh[] = { "S" ,"L" ,"R" ,"I" };
|
||||||
|
const std::string lf[] = { "I" , "L" , "R" , "S" };
|
||||||
|
const std::string rh[] = { "S" , "R" , "L" , "I" };
|
||||||
|
const std::string rf[] = { "I" , "R" , "L" , "S" };
|
||||||
|
|
||||||
|
std::vector<std::string> v_lh(std::begin(lh), std::end(lh));
|
||||||
|
std::vector<std::string> v_lf(std::begin(lf), std::end(lf));
|
||||||
|
std::vector<std::string> v_rh(std::begin(rh), std::end(rh));
|
||||||
|
std::vector<std::string> v_rf(std::begin(rf), std::end(rf));
|
||||||
|
|
||||||
|
std::vector<std::vector<std::string>> retList;
|
||||||
|
retList.push_back(v_lh);
|
||||||
|
retList.push_back(v_lf);
|
||||||
|
retList.push_back(v_rh);
|
||||||
|
retList.push_back(v_rh);
|
||||||
|
|
||||||
|
for (int i = 0; i < ORIEN_NUM; i++)
|
||||||
|
{
|
||||||
|
OrientationHelper::orien_map.insert(std::pair<std::string, std::vector<std::string>>(indexList.at(i), retList.at(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string>* OrientationHelper::getOrientationStrList(const std::string &index)
|
||||||
|
{
|
||||||
|
|
||||||
|
const char* s = index.c_str();
|
||||||
|
int len = strlen(s);
|
||||||
|
char *hint = new char[len + 1];
|
||||||
|
strcpy_s(hint, len + 1, s);
|
||||||
|
|
||||||
|
std::string trim = StringFilter(hint);
|
||||||
|
OrientationMapType::iterator it = OrientationHelper::orien_map.find(trim);
|
||||||
|
delete hint;
|
||||||
|
|
||||||
|
if (it == orien_map.end())
|
||||||
|
{
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return &(it->second);
|
||||||
|
}
|
||||||
19
src/src/Common/Helper/OrientationHelper.h
Normal file
19
src/src/Common/Helper/OrientationHelper.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// Created by Krad on 2022/9/20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef OMEGAV_ORIENTATIONHELPER_H
|
||||||
|
#define OMEGAV_ORIENTATIONHELPER_H
|
||||||
|
#include "Common/QGlobals.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
typedef std::map<std::string,std::vector<std::string>> OrientationMapType;
|
||||||
|
class OrientationHelper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::string StringFilter(char* str);
|
||||||
|
static void init();
|
||||||
|
static std::vector<std::string>* getOrientationStrList(const std::string &index);
|
||||||
|
static OrientationMapType orien_map;
|
||||||
|
};
|
||||||
|
#endif //OMEGAV_ORIENTATIONHELPER_H
|
||||||
90
src/src/Common/ImageSetStore.cpp
Normal file
90
src/src/Common/ImageSetStore.cpp
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
//
|
||||||
|
// Created by Krad on 2022/9/20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "ImageSetStore.h"
|
||||||
|
|
||||||
|
#include "SeriesImageSet.h"
|
||||||
|
#include "IO/DICOM/DicomLoader.h"
|
||||||
|
#include "IO/DICOM/ExtendMedicalImageProperties.h"
|
||||||
|
|
||||||
|
SeriesImageSet *ImageSetStore::getSeriesImageSet(const string &uniqueID) {
|
||||||
|
//only user key to the series level
|
||||||
|
if (store.count(uniqueID)>0)
|
||||||
|
{
|
||||||
|
//use cache instead load
|
||||||
|
return store[uniqueID];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto iter = std::find_if(imageProperties.begin(), imageProperties.end(),[&uniqueID](auto property){
|
||||||
|
return property->GetUniqueID()==uniqueID;
|
||||||
|
});
|
||||||
|
if (iter==imageProperties.end()) return nullptr;
|
||||||
|
vtkSmartPointer<vtkImageData> pixelData;
|
||||||
|
vtkSmartPointer<vtkImageData> overlayData;
|
||||||
|
DicomLoader::InitCodecs();
|
||||||
|
DicomLoader::getImageData(*iter, pixelData, overlayData);
|
||||||
|
SeriesImageSet* set = new SeriesImageSet(*iter,pixelData);
|
||||||
|
if (overlayData.Get()){
|
||||||
|
set->SetOverlayData(overlayData);
|
||||||
|
}
|
||||||
|
DicomLoader::FinalizeCodecs();
|
||||||
|
store[uniqueID] = set;
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageSetStore::reset() {
|
||||||
|
for(auto item: store){
|
||||||
|
delete item.second;
|
||||||
|
}
|
||||||
|
store.clear();
|
||||||
|
for(auto item: m_patients){
|
||||||
|
delete item.second;
|
||||||
|
}
|
||||||
|
m_patients.clear();
|
||||||
|
if (placeHolder)placeHolder->Delete();
|
||||||
|
placeHolder = vtkObject::New();
|
||||||
|
imageProperties.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageSetStore::addImageSet(ExtendMedicalImageProperties* property) {
|
||||||
|
std::string patient_name = property->GetPatientName();
|
||||||
|
std::string study_uid = property->GetStudyUID();
|
||||||
|
std::string series_uid = property->GetSeriesUID();
|
||||||
|
//patient level
|
||||||
|
PatientInfo_t* patient = nullptr;
|
||||||
|
//get from store
|
||||||
|
if (m_patients.count(patient_name)>0){
|
||||||
|
patient = m_patients[patient_name];
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
//create new
|
||||||
|
patient = new PatientInfo_t();
|
||||||
|
patient->patient_name = property->GetPatientName();
|
||||||
|
patient->birth_date = property->GetPatientBirthDate();
|
||||||
|
patient->studies = new StudiesMapType();
|
||||||
|
m_patients[patient_name] = patient;
|
||||||
|
}
|
||||||
|
StudyInfo_t* study = nullptr;
|
||||||
|
//get from store
|
||||||
|
if (patient->studies->count(study_uid)>0){
|
||||||
|
study = patient->studies->at(study_uid);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
//create new
|
||||||
|
study = new StudyInfo_t();
|
||||||
|
patient->studies->insert({study_uid, study});
|
||||||
|
study->study_description = property->GetStudyDescription();
|
||||||
|
study->study_date = property->GetStudyDate();
|
||||||
|
study->study_time = property->GetStudyTime();
|
||||||
|
study->series = new SeriesMapType();
|
||||||
|
}
|
||||||
|
//TODO:need add Image set logic
|
||||||
|
if (study->series->count(series_uid)>0){
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
study->series->insert({series_uid,property});
|
||||||
|
imageProperties.push_back(property);
|
||||||
|
}
|
||||||
|
}
|
||||||
41
src/src/Common/ImageSetStore.h
Normal file
41
src/src/Common/ImageSetStore.h
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
//
|
||||||
|
// Created by Krad on 2022/9/20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef OMEGAV_IMAGESETSTORE_H
|
||||||
|
#define OMEGAV_IMAGESETSTORE_H
|
||||||
|
|
||||||
|
#include "Common/QGlobals.h"
|
||||||
|
class SeriesImageSet;
|
||||||
|
class ExtendMedicalImageProperties;
|
||||||
|
typedef std::map<std::string, SeriesImageSet*> StoreMap;
|
||||||
|
class ImageSetStore {
|
||||||
|
public:
|
||||||
|
static ImageSetStore *GetInstance(){
|
||||||
|
static ImageSetStore store;
|
||||||
|
return &store;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PatientsMapType &getPatientsList()
|
||||||
|
{
|
||||||
|
return m_patients;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addImageSet(ExtendMedicalImageProperties* property);
|
||||||
|
|
||||||
|
SeriesImageSet* getSeriesImageSet(const std::string& uniqueID);
|
||||||
|
std::vector<ExtendMedicalImageProperties*>& getProperties(){
|
||||||
|
return imageProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
private:
|
||||||
|
std::vector<ExtendMedicalImageProperties*> imageProperties;
|
||||||
|
StoreMap store;
|
||||||
|
PatientsMapType m_patients;
|
||||||
|
vtkObject* placeHolder;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif //OMEGAV_IMAGESETSTORE_H
|
||||||
@@ -10,9 +10,9 @@
|
|||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
SeriesImageSet::SeriesImageSet(ExtendMedicalImageProperties* property, vtkImageData* imagedata)
|
SeriesImageSet::SeriesImageSet(ExtendMedicalImageProperties* property, vtkImageData* imagedata):QObject(nullptr)
|
||||||
|
,m_image(imagedata)
|
||||||
{
|
{
|
||||||
m_image = imagedata;
|
|
||||||
m_image->SetSpacing(property->GetSpacing());
|
m_image->SetSpacing(property->GetSpacing());
|
||||||
m_property = property;
|
m_property = property;
|
||||||
m_pUniqueID.append(property->GetPatientName());
|
m_pUniqueID.append(property->GetPatientName());
|
||||||
|
|||||||
@@ -38,9 +38,6 @@ ExtendMedicalImageProperties *DICOMHeaderHelper::GetSeriesBySeriesUID(const char
|
|||||||
void DICOMHeaderHelper::Clear() {
|
void DICOMHeaderHelper::Clear() {
|
||||||
dirName.clear();
|
dirName.clear();
|
||||||
fileName.clear();
|
fileName.clear();
|
||||||
for (auto property : seriesProperties) {
|
|
||||||
property->Delete();
|
|
||||||
}
|
|
||||||
seriesProperties.clear();
|
seriesProperties.clear();
|
||||||
SeriesCount = 0;
|
SeriesCount = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,241 +1,59 @@
|
|||||||
#include "DicomLoader.h"
|
#include "DicomLoader.h"
|
||||||
|
|
||||||
#include <map>
|
#include <vtkNew.h>
|
||||||
#include <algorithm>
|
#include <vtkImageData.h>
|
||||||
#include <vtkStringArray.h>
|
|
||||||
#include <QDebug>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "Common/SeriesImageSet.h"
|
|
||||||
#include "DICOMHeaderHelper.h"
|
#include "DICOMHeaderHelper.h"
|
||||||
|
#include "DICOMPixelDataHelper.h"
|
||||||
#include "vtkDCMTKImageReader.h"
|
#include "vtkDCMTKImageReader.h"
|
||||||
|
|
||||||
#define ORIEN_NUM 4
|
|
||||||
#define SINGLE_INSTANCE 1
|
|
||||||
OrientationMapType orientationHelper::orien_map;
|
|
||||||
|
|
||||||
/************************************************************************
|
void DicomLoader::readPropertiesFromDir(const std::string &dir,
|
||||||
* [Q]Is there anything different between these two?
|
std::vector<ExtendMedicalImageProperties*>& properties, int& count) {
|
||||||
* instance->m_image = m_itkConnector->GetOutput();
|
|
||||||
* instance->m_image->DeepCopy(m_itkConnector->GetOutput());
|
|
||||||
* [Q]I have no idea why it works just fine not using deep copy,
|
|
||||||
while the vtkdata is replaced in the Qfusion Project using exatly the same workflow!
|
|
||||||
/************************************************************************/
|
|
||||||
std::string orientationHelper::StringFilter(char* str)
|
|
||||||
{
|
|
||||||
const char s[] = "\\ ";
|
|
||||||
char *token;
|
|
||||||
char *buftmp;
|
|
||||||
token = strtok_s(str, s, &buftmp);
|
|
||||||
std::string trim ="";
|
|
||||||
while (token != NULL) {
|
|
||||||
//printf("%s\n", token);
|
|
||||||
trim += token;
|
|
||||||
token = strtok_s(NULL, s, &buftmp);
|
|
||||||
}
|
|
||||||
return trim;
|
|
||||||
}
|
|
||||||
|
|
||||||
void orientationHelper::init()
|
|
||||||
{
|
|
||||||
const std::string index[] = { "LH","LF","RH","RF" };
|
|
||||||
std::vector<std::string> indexList(std::begin(index), std::end(index));
|
|
||||||
|
|
||||||
const std::string lh[] = { "S" ,"L" ,"R" ,"I" };
|
|
||||||
const std::string lf[] = { "I" , "L" , "R" , "S" };
|
|
||||||
const std::string rh[] = { "S" , "R" , "L" , "I" };
|
|
||||||
const std::string rf[] = { "I" , "R" , "L" , "S" };
|
|
||||||
|
|
||||||
std::vector<std::string> v_lh(std::begin(lh), std::end(lh));
|
|
||||||
std::vector<std::string> v_lf(std::begin(lf), std::end(lf));
|
|
||||||
std::vector<std::string> v_rh(std::begin(rh), std::end(rh));
|
|
||||||
std::vector<std::string> v_rf(std::begin(rf), std::end(rf));
|
|
||||||
|
|
||||||
std::vector<std::vector<std::string>> retList;
|
|
||||||
retList.push_back(v_lh);
|
|
||||||
retList.push_back(v_lf);
|
|
||||||
retList.push_back(v_rh);
|
|
||||||
retList.push_back(v_rh);
|
|
||||||
|
|
||||||
for (int i = 0; i < ORIEN_NUM; i++)
|
|
||||||
{
|
|
||||||
orientationHelper::orien_map.insert(std::pair<std::string, std::vector<std::string>>(indexList.at(i), retList.at(i)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string>* orientationHelper::getOrientationStrList(const std::string &index)
|
|
||||||
{
|
|
||||||
|
|
||||||
const char* s = index.c_str();
|
|
||||||
int len = strlen(s);
|
|
||||||
char *hint = new char[len + 1];
|
|
||||||
strcpy_s(hint, len + 1, s);
|
|
||||||
|
|
||||||
std::string trim = StringFilter(hint);
|
|
||||||
OrientationMapType::iterator it = orientationHelper::orien_map.find(trim);
|
|
||||||
delete hint;
|
|
||||||
|
|
||||||
if (it == orien_map.end())
|
|
||||||
{
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return &(it->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
DicomLoader* DicomLoader::instance = new DicomLoader();
|
|
||||||
DicomLoader* DicomLoader::GetInstance() {
|
|
||||||
//lazy man
|
|
||||||
//if (!instance) {
|
|
||||||
// instance = new DicomLoader();
|
|
||||||
//}
|
|
||||||
//hungry man
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
DicomLoader::DicomLoader(){
|
|
||||||
|
|
||||||
// m_itkSeriesReader = SeriesReaderType::New();
|
|
||||||
// m_itkConnector = ConnectorType::New();
|
|
||||||
// m_gdcmIO = ImageIOType::New();
|
|
||||||
// m_inputNames = InputNamesGeneratorType::New();
|
|
||||||
|
|
||||||
reader = nullptr;
|
|
||||||
//transfer to series after!
|
|
||||||
m_patients.clear();
|
|
||||||
placeHolder = vtkObject::New();
|
|
||||||
defaultUniqueID = "";
|
|
||||||
}
|
|
||||||
DicomLoader::~DicomLoader() {
|
|
||||||
|
|
||||||
placeHolder->Delete();
|
|
||||||
imageProperties.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SeriesImageSet* DicomLoader::getSeriesImageSet(const std::string& uniqueID)//, DicomTagInfo_t* tag_info)
|
|
||||||
{
|
|
||||||
//only user key to the series level
|
|
||||||
if (store.count(uniqueID)>0)
|
|
||||||
{
|
|
||||||
//use cache instead load
|
|
||||||
return store[uniqueID];
|
|
||||||
}
|
|
||||||
if (reader) reader->Delete();
|
|
||||||
reader = vtkDCMTKImageReader::New();
|
|
||||||
auto iter = std::find_if(imageProperties.begin(), imageProperties.end(),[&uniqueID](auto property){
|
|
||||||
return property->GetUniqueID()==uniqueID;
|
|
||||||
});
|
|
||||||
if (iter==imageProperties.end()) return nullptr;
|
|
||||||
|
|
||||||
// reader->SetFileNames((*iter)->GetFileNames());
|
|
||||||
reader->SetImageProperties((*iter));
|
|
||||||
reader->Update();
|
|
||||||
auto imageData = reader->GetOutput();
|
|
||||||
SeriesImageSet* result = new SeriesImageSet((*iter),imageData);
|
|
||||||
if (reader->GetHasOverlay()){
|
|
||||||
result->SetOverlayData(reader->GetOutputOverLayData());
|
|
||||||
}
|
|
||||||
// imageData->Register(placeHolder);
|
|
||||||
reader->Delete();
|
|
||||||
reader = nullptr;
|
|
||||||
store[uniqueID] = result;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DicomLoader::readTags(const std::string &dir, SeriesOpenMode openMode)
|
|
||||||
{
|
|
||||||
DICOMHeaderHelper DICOMHelper;
|
DICOMHeaderHelper DICOMHelper;
|
||||||
if (openMode == FILE_OPEN_MODE)
|
DICOMHelper.SetDirName(dir.c_str());
|
||||||
{
|
DICOMHelper.Update();
|
||||||
//m_itkSeriesReader->SetFileName(m_dicomName.toStdString());
|
count = DICOMHelper.GetSeriesCount();
|
||||||
DICOMHelper.SetFileName(dir.c_str());
|
|
||||||
}
|
|
||||||
if (openMode == DIR_OPEN_MODE)
|
|
||||||
{
|
|
||||||
DICOMHelper.SetDirName(dir.c_str());
|
|
||||||
}
|
|
||||||
DICOMHelper.Update();
|
|
||||||
if ( DICOMHelper.GetSeriesCount()>0){
|
if ( DICOMHelper.GetSeriesCount()>0){
|
||||||
for (auto item : DICOMHelper.GetSeriesProperties()) {
|
for (auto item : DICOMHelper.GetSeriesProperties()) {
|
||||||
item->Register(placeHolder);
|
properties.push_back(item);
|
||||||
imageProperties.push_back(item);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( imageProperties.size() > 0 ) {
|
|
||||||
currentImageProperty = imageProperties[0];
|
|
||||||
defaultUniqueID = currentImageProperty->GetUniqueID();
|
|
||||||
readSeries();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DicomLoader::readPropertiesFromFile(const std::string &file,
|
||||||
void DicomLoader::readSeries() {
|
std::vector<ExtendMedicalImageProperties*>& properties, int& count) {
|
||||||
|
DICOMHeaderHelper DICOMHelper;
|
||||||
for (ExtendMedicalImageProperties* property: imageProperties){
|
DICOMHelper.SetFileName(file.c_str());
|
||||||
|
DICOMHelper.Update();
|
||||||
std::string patient_name = property->GetPatientName();
|
count = DICOMHelper.GetSeriesCount();
|
||||||
std::string study_uid = property->GetStudyUID();
|
if ( DICOMHelper.GetSeriesCount()>0){
|
||||||
std::string series_uid = property->GetSeriesUID();
|
for (auto item : DICOMHelper.GetSeriesProperties()) {
|
||||||
//patient level
|
properties.push_back(item);
|
||||||
PatientInfo_t* patient = nullptr;
|
|
||||||
//get from store
|
|
||||||
if (m_patients.count(patient_name)>0){
|
|
||||||
patient = m_patients[patient_name];
|
|
||||||
}
|
}
|
||||||
else{
|
|
||||||
//create new
|
|
||||||
patient = new PatientInfo_t();
|
|
||||||
patient->patient_name = property->GetPatientName();
|
|
||||||
patient->birth_date = property->GetPatientBirthDate();
|
|
||||||
patient->studies = new StudiesMapType();
|
|
||||||
m_patients[patient_name] = patient;
|
|
||||||
}
|
|
||||||
StudyInfo_t* study = nullptr;
|
|
||||||
//get from store
|
|
||||||
if (patient->studies->count(study_uid)>0){
|
|
||||||
study = patient->studies->at(study_uid);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
//create new
|
|
||||||
study = new StudyInfo_t();
|
|
||||||
patient->studies->insert({study_uid, study});
|
|
||||||
study->study_description = property->GetStudyDescription();
|
|
||||||
study->study_date = property->GetStudyDate();
|
|
||||||
study->study_time = property->GetStudyTime();
|
|
||||||
study->series = new SeriesMapType();
|
|
||||||
}
|
|
||||||
if (study->series->count(series_uid)>0){
|
|
||||||
// series = study->series->at(series_uid);
|
|
||||||
//TODO:need to add override logic!!
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
study->series->insert({series_uid,property});
|
|
||||||
|
|
||||||
// double *wlww = property->GetNthWindowLevelPreset(0);
|
|
||||||
// int ww = wlww ? ((int) wlww[0]) : (512);
|
|
||||||
// int wl = wlww ? ((int) wlww[1]) : (256);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DicomLoader::reset() {
|
void DicomLoader::getImageData(ExtendMedicalImageProperties *property,
|
||||||
|
vtkSmartPointer<vtkImageData>& pixelData, vtkSmartPointer<vtkImageData>& overlayData) {
|
||||||
currentImageProperty = nullptr;
|
vtkNew<vtkDCMTKImageReader> reader;
|
||||||
reader = nullptr;
|
reader->SetImageProperties(property);
|
||||||
for(auto item: store){
|
reader->Update();
|
||||||
delete item.second;
|
pixelData = reader->GetOutput();
|
||||||
}
|
overlayData = reader->GetOutputOverLayData();
|
||||||
store.clear();
|
}
|
||||||
for(auto item: m_patients){
|
|
||||||
delete item.second;
|
void DicomLoader::InitCodecs() {
|
||||||
}
|
DICOMPixelDataHelper::InitCodecs();
|
||||||
m_patients.clear();
|
}
|
||||||
placeHolder->Delete();
|
|
||||||
placeHolder = vtkObject::New();
|
void DicomLoader::FinalizeCodecs() {
|
||||||
imageProperties.clear();
|
DICOMPixelDataHelper::FinalizeCodecs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DicomLoader::getThumbnailData(ExtendMedicalImageProperties* property,void*& data, int& sample) {
|
||||||
|
unsigned long l ;
|
||||||
|
DICOMPixelDataHelper::GetThumbnailData(property, data,l,sample);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,77 +1,32 @@
|
|||||||
#ifndef OMEGAV_DICOMLOADER_H
|
#ifndef OMEGAV_DICOMLOADER_H
|
||||||
#define OMEGAV_DICOMLOADER_H
|
#define OMEGAV_DICOMLOADER_H
|
||||||
|
|
||||||
#pragma once
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <vtkSmartPointer.h>
|
||||||
|
|
||||||
#include "Common/QGlobals.h"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
typedef std::map<std::string,std::vector<std::string>> OrientationMapType;
|
|
||||||
class orientationHelper
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static std::string StringFilter(char* str);
|
|
||||||
static void init();
|
|
||||||
static std::vector<std::string>* getOrientationStrList(const std::string &index);
|
|
||||||
static OrientationMapType orien_map;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SeriesImageSet;
|
|
||||||
|
|
||||||
|
|
||||||
class DICOMHeaderHelper;
|
|
||||||
class ExtendMedicalImageProperties;
|
class ExtendMedicalImageProperties;
|
||||||
class vtkDCMTKImageReader;
|
class vtkImageData;
|
||||||
typedef std::map<std::string, SeriesImageSet*> ImageSetStore;
|
|
||||||
|
|
||||||
class DicomLoader {
|
class DicomLoader {
|
||||||
public:
|
public:
|
||||||
|
static void InitCodecs();
|
||||||
|
|
||||||
static DicomLoader *GetInstance();
|
static void FinalizeCodecs();
|
||||||
|
|
||||||
/**
|
static void readPropertiesFromDir(const std::string &dir,
|
||||||
* 读取数据Tag
|
std::vector<ExtendMedicalImageProperties*>& properties, int& count);
|
||||||
* @param dir
|
|
||||||
* @param openMode
|
|
||||||
*/
|
|
||||||
void readTags(const std::string &dir, SeriesOpenMode openMode);
|
|
||||||
|
|
||||||
const std::string& getDefaultUniqueID(){
|
static void readPropertiesFromFile(const std::string &file,
|
||||||
return defaultUniqueID;
|
std::vector<ExtendMedicalImageProperties*>& properties, int& count);
|
||||||
}
|
|
||||||
|
|
||||||
const PatientsMapType &getPatientsList()
|
static void getImageData(ExtendMedicalImageProperties* property,
|
||||||
{
|
vtkSmartPointer<vtkImageData>& pixelData, vtkSmartPointer<vtkImageData>& overlayData);
|
||||||
return m_patients;
|
|
||||||
}
|
|
||||||
|
|
||||||
SeriesImageSet* getSeriesImageSet(const std::string& uniqueID);
|
|
||||||
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
|
static void getThumbnailData(ExtendMedicalImageProperties* property,void*& data, int& sample);
|
||||||
private:
|
private:
|
||||||
explicit DicomLoader();
|
DicomLoader() = delete;
|
||||||
~DicomLoader();
|
~DicomLoader() = delete;
|
||||||
|
|
||||||
/**
|
|
||||||
* 本函数根据DICOM文件TagValue来构建一个树状的PSSI结构
|
|
||||||
* 即:Patient-Study-Series-Image
|
|
||||||
* 主要用途是为左侧的thumbnail bar 做数据支撑
|
|
||||||
* TODO:目前Image层暂缺
|
|
||||||
*/
|
|
||||||
void readSeries();
|
|
||||||
|
|
||||||
static DicomLoader *instance;
|
|
||||||
|
|
||||||
//once
|
|
||||||
|
|
||||||
ExtendMedicalImageProperties * currentImageProperty = nullptr;
|
|
||||||
std::vector<ExtendMedicalImageProperties*> imageProperties;
|
|
||||||
vtkDCMTKImageReader * reader = nullptr;
|
|
||||||
ImageSetStore store;
|
|
||||||
std::string defaultUniqueID;
|
|
||||||
PatientsMapType m_patients;
|
|
||||||
vtkObject* placeHolder;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif OMEGAV_DICOMLOADER_H
|
#endif OMEGAV_DICOMLOADER_H
|
||||||
|
|||||||
19
src/src/IO/Defines/DIDKitExport.h
Normal file
19
src/src/IO/Defines/DIDKitExport.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// Created by Krad on 2022/9/19.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef OMEGAV_DIDKITEXPORT_H
|
||||||
|
#define OMEGAV_DIDKITEXPORT_H
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#ifdef DIDKIT_SHARED
|
||||||
|
/* Defines needed for building DLLs on windows */
|
||||||
|
#define DIDKIT_EXPORT __declspec(dllexport)
|
||||||
|
#elif USE_DIDKIT
|
||||||
|
/* Defines needed for use DLLs on windows */
|
||||||
|
#define DIDKIT_EXPORT __declspec(dllimport)
|
||||||
|
#else
|
||||||
|
#define DIDKIT_EXPORT
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif //OMEGAV_DIDKITEXPORT_H
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QVTKOpenGLNativeWidget.h>
|
#include <QVTKOpenGLNativeWidget.h>
|
||||||
|
|
||||||
#include "IO/DICOM/DicomLoader.h"
|
#include "Common/ImageSetStore.h"
|
||||||
#include "Interaction/ActorDraggableInteractorStyle.h"
|
#include "Interaction/ActorDraggableInteractorStyle.h"
|
||||||
#include "Rendering/Measure/MeasureFactory.h"
|
#include "Rendering/Measure/MeasureFactory.h"
|
||||||
#include "UI/Widget/ImageView/ViewContainerWidget.h"
|
#include "UI/Widget/ImageView/ViewContainerWidget.h"
|
||||||
@@ -359,7 +359,7 @@ void ImageViewManager::viewEndWindowLevel(DicomImageView *src, double level, dou
|
|||||||
void ImageViewManager::viewReload(const std::string &unique_info) {
|
void ImageViewManager::viewReload(const std::string &unique_info) {
|
||||||
if (!currentView) return;
|
if (!currentView) return;
|
||||||
currentView->unloadFusion();
|
currentView->unloadFusion();
|
||||||
DicomLoader *helper = DicomLoader::GetInstance();
|
ImageSetStore *helper = ImageSetStore::GetInstance();
|
||||||
currentView->loadSeries(helper->getSeriesImageSet(unique_info));
|
currentView->loadSeries(helper->getSeriesImageSet(unique_info));
|
||||||
currentView->render();
|
currentView->render();
|
||||||
reloadCurrentView(currentView);
|
reloadCurrentView(currentView);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include "qstyleoption.h"
|
#include "qstyleoption.h"
|
||||||
#include "qpainter.h"
|
#include "qpainter.h"
|
||||||
#include "IO/DICOM/DICOMPixelDataHelper.h"
|
#include "IO/DICOM/DicomLoader.h"
|
||||||
|
|
||||||
static QString unpick_style = "*{background-color:#7f7f7f;}"
|
static QString unpick_style = "*{background-color:#7f7f7f;}"
|
||||||
"QLabel#m_descri{color:white}";
|
"QLabel#m_descri{color:white}";
|
||||||
@@ -134,9 +134,8 @@ thumbnailImage::~thumbnailImage()
|
|||||||
void thumbnailImage::drawThumbnail() {
|
void thumbnailImage::drawThumbnail() {
|
||||||
if (m_Data) free(m_Data);
|
if (m_Data) free(m_Data);
|
||||||
m_Data = nullptr;
|
m_Data = nullptr;
|
||||||
unsigned long length = 0;
|
|
||||||
int sample = 0;
|
int sample = 0;
|
||||||
DICOMPixelDataHelper::GetThumbnailData(seriesProperty, m_Data, length, sample);
|
DicomLoader::getThumbnailData(seriesProperty, m_Data, sample);
|
||||||
QImage image( (uchar*)m_Data, seriesProperty->GetColumns(), seriesProperty->GetRows(),
|
QImage image( (uchar*)m_Data, seriesProperty->GetColumns(), seriesProperty->GetRows(),
|
||||||
sample == 1 ? QImage::Format_Grayscale8 : QImage::Format_RGB888);//使用8位深度的灰度图做输出
|
sample == 1 ? QImage::Format_Grayscale8 : QImage::Format_RGB888);//使用8位深度的灰度图做输出
|
||||||
image = image.scaledToHeight(100);
|
image = image.scaledToHeight(100);
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
#include <qstyleoption.h>
|
#include <qstyleoption.h>
|
||||||
#include <qpainter.h>
|
#include <qpainter.h>
|
||||||
|
|
||||||
|
#include "Common/ImageSetStore.h"
|
||||||
#include "IO/DICOM/DicomLoader.h"
|
#include "IO/DICOM/DicomLoader.h"
|
||||||
#include "IO/DICOM/DICOMPixelDataHelper.h"
|
|
||||||
#include "Common/SeriesImageSet.h"
|
#include "Common/SeriesImageSet.h"
|
||||||
#include "UI/Widget/ImageView/dicomimageview.h"
|
#include "UI/Widget/ImageView/dicomimageview.h"
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ void ThumbnailBarWidget::updateThumbnailBar()
|
|||||||
}
|
}
|
||||||
clear();
|
clear();
|
||||||
bool firstThumbnail = true;
|
bool firstThumbnail = true;
|
||||||
DicomLoader *helper = DicomLoader::GetInstance();
|
ImageSetStore *helper = ImageSetStore::GetInstance();
|
||||||
//获取Patient
|
//获取Patient
|
||||||
const PatientsMapType & all_patients = helper->getPatientsList();
|
const PatientsMapType & all_patients = helper->getPatientsList();
|
||||||
for (PatientsMapType::const_iterator it_pa = all_patients.cbegin(); it_pa != all_patients.cend(); it_pa++) {
|
for (PatientsMapType::const_iterator it_pa = all_patients.cbegin(); it_pa != all_patients.cend(); it_pa++) {
|
||||||
@@ -116,7 +116,7 @@ void ThumbnailBarWidget::updateThumbnailBar()
|
|||||||
|
|
||||||
SeriesMapType *series = it_st->second->series;
|
SeriesMapType *series = it_st->second->series;
|
||||||
|
|
||||||
DICOMPixelDataHelper::InitCodecs();
|
DicomLoader::InitCodecs();
|
||||||
for (SeriesMapType::const_iterator it_se = series->cbegin(); it_se != series->cend(); it_se++) {
|
for (SeriesMapType::const_iterator it_se = series->cbegin(); it_se != series->cend(); it_se++) {
|
||||||
thumbnailImage *thumbnail = createThumbnailImage(seriesPanel, it_se->second);
|
thumbnailImage *thumbnail = createThumbnailImage(seriesPanel, it_se->second);
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ void ThumbnailBarWidget::updateThumbnailBar()
|
|||||||
//save all thumbnail in one list
|
//save all thumbnail in one list
|
||||||
LabelList << thumbnail;
|
LabelList << thumbnail;
|
||||||
}
|
}
|
||||||
DICOMPixelDataHelper::FinalizeCodecs();
|
DicomLoader::FinalizeCodecs();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,9 @@
|
|||||||
#include <QButtonGroup>
|
#include <QButtonGroup>
|
||||||
|
|
||||||
|
|
||||||
|
#include "Common/Helper/OrientationHelper.h"
|
||||||
|
#include "Common/ImageSetStore.h"
|
||||||
|
#include "IO/DICOM/DicomLoader.h"
|
||||||
#include "Interaction/ActorDraggableInteractorStyle.h"
|
#include "Interaction/ActorDraggableInteractorStyle.h"
|
||||||
#include "UI/Manager/ImageViewManager.h"
|
#include "UI/Manager/ImageViewManager.h"
|
||||||
#include "UI/Widget/Component/gridpopwidget.h"
|
#include "UI/Widget/Component/gridpopwidget.h"
|
||||||
@@ -39,7 +42,7 @@ QDicomViewer::QDicomViewer(QWidget *parent) : QMainWindow(parent),
|
|||||||
displayThumbnailBar(false);
|
displayThumbnailBar(false);
|
||||||
|
|
||||||
//TODO:目前为方向是写死的正交方向
|
//TODO:目前为方向是写死的正交方向
|
||||||
orientationHelper::init();
|
OrientationHelper::init();
|
||||||
}
|
}
|
||||||
|
|
||||||
QDicomViewer::~QDicomViewer() {
|
QDicomViewer::~QDicomViewer() {
|
||||||
@@ -272,14 +275,24 @@ void QDicomViewer::openDICOM(const std::string &dicomName, SeriesOpenMode openMo
|
|||||||
|
|
||||||
//必须首先重置成1个窗口的布局
|
//必须首先重置成1个窗口的布局
|
||||||
ui->viewContainer->resetLayoutToSingle();
|
ui->viewContainer->resetLayoutToSingle();
|
||||||
//数据读取
|
|
||||||
DicomLoader *helper = DicomLoader::GetInstance();
|
|
||||||
helper->reset();
|
|
||||||
//load image and tag
|
|
||||||
helper->readTags(dicomName, openMode);
|
|
||||||
auto unique = helper->getDefaultUniqueID();
|
|
||||||
|
|
||||||
ui->viewContainer->getViewManager()->viewReload(unique);
|
//reset store
|
||||||
|
ImageSetStore *helper = ImageSetStore::GetInstance();
|
||||||
|
helper->reset();
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
std::vector<ExtendMedicalImageProperties*> vector;
|
||||||
|
if (openMode == SeriesOpenMode::DIR_OPEN_MODE){
|
||||||
|
DicomLoader::readPropertiesFromDir(dicomName, vector,count);
|
||||||
|
}else{
|
||||||
|
DicomLoader::readPropertiesFromFile(dicomName, vector, count);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
helper->addImageSet(vector[i]);
|
||||||
|
}
|
||||||
|
if (count > 0){
|
||||||
|
ui->viewContainer->getViewManager()->viewReload(vector[0]->GetUniqueID());
|
||||||
|
}
|
||||||
ui->thumbnailBar->updateThumbnailBar();
|
ui->thumbnailBar->updateThumbnailBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user