DicomViewer (dcmtk读取dcm文件)5

1背景

上一篇将选择的文件传入了后台线程中,这一篇继续处理解析文件的。

2 正文

2.1 DicomReader 增加读取文件的方法

c++ 复制代码
#pragma once
#include <memory>
#include <string>

#include <dcmtk/dcmdata/dcfilefo.h>

#include "core/model/Image.h"
#include "core/model/Patient.h"
#include "core/model/Series.h"
#include "core/model/Study.h"
#include "dcmtk/dcmdata/dcdatset.h"
#include "dcmtk/dcmdata/dctagkey.h"

class DicomReader
{
public:
explicit DicomReader();
~DicomReader() = default;

public:
void readFile(const std::string& t_filePath);
bool dataSetExist() const;
std::unique_ptr<Patient> getReadPatient() const;
std::unique_ptr<Study> getReadStudy() const;
std::unique_ptr<Series> getReadSeries() const;
std::unique_ptr<Image> getReadImage() const;

private:
std::string m_filePath;
DcmDataset* m_dataSet;
std::unique_ptr<DcmFileFormat> m_file;

std::string getTagFromDataSet(const DcmTagKey& tagKey) const;
static bool isModalitySupported(const std::string& t_modality);
};

除了存储dcm文件地址,还有dcm信息读取并封装成对应的类,以及读取tag的公用方法。 DcmDataset只能用普通指针,因为类库读取的就是普通的指针。

2.2 DicomReader读取文件的定义

这里先实现读取文件,其他的先写个空的,防止编译报错

c++ 复制代码
#include <memory>
#include <stdexcept>

#include "DicomReader.h"

#include "core/model/Image.h"
#include "core/model/Patient.h"
#include "core/model/Series.h"
#include "core/model/Study.h"
#include "dcmtk/dcmdata/dcfilefo.h"

DicomReader::DicomReader() {}

void DicomReader::readFile(const std::string& t_filePath)
{
  m_filePath = t_filePath;
  m_file = std::make_unique<DcmFileFormat>();
  if (m_file->loadFile(t_filePath.c_str()).bad()) {
    m_file.release();
    m_dataSet = nullptr;
    throw std::runtime_error("Cannot open file !");
  }
  m_dataSet = m_file->getDataset();
}

bool DicomReader::dataSetExist() const
{
  return m_dataSet != nullptr;
}

std::unique_ptr<Patient> DicomReader::getReadPatient() const
{
  auto t_patient = std::make_unique<Patient>();
  return t_patient;
}

std::unique_ptr<Study> DicomReader::getReadStudy() const
{
  auto t_study = std::make_unique<Study>();
  return t_study;
}

std::unique_ptr<Series> DicomReader::getReadSeries() const
{
  auto t_series = std::make_unique<Series>();
  return t_series;
}

std::unique_ptr<Image> DicomReader::getReadImage() const
{
  auto t_image = std::make_unique<Image>();
  return t_image;
}

std::string DicomReader::getTagFromDataSet(const DcmTagKey& tagKey) const
{
  auto t_tag = "";
  return t_tag;
}

bool DicomReader::isModalitySupported(const std::string& t_modality)
{
  return true;
}

复制文件路径,并读取,如果读取失败则释放,否则读取数据集。

2.3 在controller中调用上面的读取文件

c++ 复制代码
#pragma once

#include <memory>
#include <string>

#include "core/lib/DicomReader.h"
#include "core/model/CoreRepository.h"

class CoreController
{
public:
  explicit CoreController();
  ~CoreController() = default;

public:
  void readData(const std::string& t_filePath) const;

private:
  std::unique_ptr<DicomReader> m_dicomReader;
  std::unique_ptr<CoreRepository> m_coreRepository;

  void insertDataInRepo() const;
};

申明DicomReader和CoreRepository独立指针,并申明dmc文件解析方法readData,这个是判断解析解析成功后存储的方法。

定义

c++ 复制代码
#include <exception>
#include <memory>
#include <stdexcept>

#include "CoreController.h"

#include "core/lib/DicomReader.h"

CoreController::CoreController()
{
  m_dicomReader = std::make_unique<DicomReader>();
  m_coreRepository = std::make_unique<CoreRepository>();
}

void CoreController::readData(const std::string& t_filePath) const
{
  try {
    m_dicomReader->readFile(t_filePath);
    auto flag = m_dicomReader->dataSetExist();
    if (flag) {
      insertDataInRepo();
    } else {
      throw std::runtime_error("File not Support!");
    }
  } catch (std::exception& ex) {
  }
}

void CoreController::insertDataInRepo() const {}

调用读取文件的方法,判断文件是否读取成功

2.4 在后台线程循环里调用解析

c++ 复制代码
#include <cstdlib>
#include <mutex>

#include "FilesImporter.h"

#include "qglobal.h"
#include "qobject.h"

FilesImporter::FilesImporter(QObject* parent)
    : QThread(Q_NULLPTR)
{
 m_coreController = std::make_unique<CoreController>();
}

void FilesImporter::startImporter()
{
  m_isWorking = true;
  start();
}

void FilesImporter::stopImporter()
{
  if (!m_isWorking) {
    return;
  }
  m_isWorking = false;
  quit();
  wait();
  m_filesPaths.clear();
}

void FilesImporter::run()
{
  while (m_isWorking) {
    importFiles();
  }
}

void FilesImporter::addFiles(const QStringList& t_paths)
{
  std::lock_guard<QMutex> lock(m_filesMutex);
  for (const auto& path : t_paths) {
    m_filesPaths.push_back(path);
  }
}

void FilesImporter::importFiles()
{
  while (!m_filesPaths.empty() && m_isWorking) {
    std::lock_guard<QMutex> lock(m_filesMutex);
    m_coreController->readData(m_filesPaths.front().toStdString());
    m_filesPaths.pop_front();
  }
}

解析文件里,先判断是否队列有文件,然后获取锁,并调用文件

ps:要初始化m_coreController,否则后面gdb调试会报错

arduino 复制代码
Thread 5 "FilesImporter" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff17516c0 (LWP 11151)]
0x0000555555560568 in std::__uniq_ptr_impl<DicomReader, std::default_delete<DicomReader> >::_M_ptr (this=0x0)
    at /usr/include/c++/13/bits/unique_ptr.h:199
199           pointer    _M_ptr() const noexcept { return std::get<0>(_M_t); }
(gdb) list
194           }
195
196           _GLIBCXX23_CONSTEXPR
197           pointer&   _M_ptr() noexcept { return std::get<0>(_M_t); }
198           _GLIBCXX23_CONSTEXPR
199           pointer    _M_ptr() const noexcept { return std::get<0>(_M_t); }
200           _GLIBCXX23_CONSTEXPR
201           _Dp&       _M_deleter() noexcept { return std::get<1>(_M_t); }
202           _GLIBCXX23_CONSTEXPR
203           const _Dp& _M_deleter() const noexcept { return std::get<1>(_M_t); }
(gdb) bt
#0  0x0000555555560568 in std::__uniq_ptr_impl<DicomReader, std::default_delete<DicomReader> >::_M_ptr (this=0x0)
    at /usr/include/c++/13/bits/unique_ptr.h:199
#1  0x000055555556047a in std::unique_ptr<DicomReader, std::default_delete<DicomReader> >::get (this=0x0)
    at /usr/include/c++/13/bits/unique_ptr.h:470
#2  0x0000555555560208 in std::unique_ptr<DicomReader, std::default_delete<DicomReader> >::operator-> (this=0x0)
    at /usr/include/c++/13/bits/unique_ptr.h:463
#3  0x000055555555fdf3 in CoreController::readData (this=0x0,
    t_filePath="/home/ubuntu/xcyxiner/DicomViewer/res/CT_small.dcm")
    at /home/ubuntu/xcyxiner/DicomViewer/source/core/controller/CoreController.cpp:19
#4  0x000055555555dcf4 in FilesImporter::importFiles (this=0x5555555c1d20)
    at /home/ubuntu/xcyxiner/DicomViewer/source/lib/FilesImporter.cpp:51
#5  0x000055555555db5a in FilesImporter::run (this=0x5555555c1d20)
    at /home/ubuntu/xcyxiner/DicomViewer/source/lib/FilesImporter.cpp:35
#6  0x00007ffff6a7c48d in ?? () from /lib/x86_64-linux-gnu/libQt6Core.so.6
#7  0x00007ffff609caa4 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:447
#8  0x00007ffff6129c6c in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78
(gdb) exit

readData 内存地址为0x0

2.5 编译

2.6 gdb断点调试

直接在控制器的解析方法打断点

arduino 复制代码
break CoreController::readData

还是选同样的文件CT_small.dcm

停在了断点的位置,顺便输出下断点附近的代码

使用p输出下当前文件地址

在一系列step后,总算进入到了readFile

next 到最后一步,没走到异常

输出下m_dataSet

输出下this以及m_file

2.7 整理提交

github commit 读取dcm文件

3 未完待续

相关推荐
xcyxiner18 小时前
DicomViewer (后台线程处理文件)4
qt
xcyxiner1 天前
DicomViewer (添加模型类)3
qt
xcyxiner2 天前
DicomViewer (目录调整) 2
qt
xcyxiner2 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
桥田智能4 天前
桥田智能 QT-650S:面向白车身焊装的 800kg 重载快换解决方案
开发语言·qt·系统架构
森G4 天前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt
森G4 天前
77、线程池原理和实现------服务器源码解析----云视频服务项目
服务器·c++·qt
森G4 天前
71、打包发布---------打包发布
c++·qt
初圣魔门首席弟子4 天前
Node.js 详细介绍(知识库版)
windows·qt·node.js·知识库