第四章 基于QT和DCMTK的Dicom 图像浏览器---检查文件夹下Dicom序列个数

12 篇文章 15 订阅
11 篇文章 13 订阅

由于mitk.net被人恶意抢注, 中科院分子影像重点实验室的www.mitk.net 改到 www.mitk.net.cn 。

目录:

开始  《DCMTK(MD版)编译和安装+VS2015》

第一章 《DCMTK(MD版)、QT、VS2015编写Dicom序列浏览应用程序-新建项目,配置环境》

第二章 《第二章 基于QT和DCMTK的Dicom 图像浏览器---界面设计》

第三章 《 基于QT和DCMTK的Dicom 图像浏览器---单个Dicom图像读取类》

第四章 《基于QT和DCMTK的Dicom 图像浏览器---检查文件夹下Dicom序列个数》

第五章 《基于QT和DCMTK的Dicom 图像浏览器---Dicom图像序列类

第六章  《基于QT和DCMTK的Dicom 图像浏览器---Dicom视图类

第七章  《基于QT和DCMTK的Dicom 图像浏览器---收尾》

一、描述

一个文件夹下(有多个DCOM单文件),可能有多个DCOM序列,每个序列有多个DCOM单文件。

series UID 是区别每个序列的标识:同Dicom序列的series UID 一样,不同序列的series UID不一样。

instanceNumber是序列内Dicom单文件的标识: instanceNumber决定了Dicom单文件在序列内的位置。

本章实现功能 “点击“选择Dicom文件夹”按钮,选择文件夹,检索文件夹下的DICOM序列个数,并初始化选择序列下拉菜单,具体见第五节

二、添加在子线程工作的类ReadWorker

添加一个QT类继承QOBJect:

1) 在项目上右键->添加->Add Qt Class ,  然后按照向导添加类 ReadWorker,如下图

 

三、编辑ReadWorker如下

#pragma once

#include <QObject>
#include <QMap>

class ReadWorker : public QObject
{
	Q_OBJECT

public:
	ReadWorker(QString DicomsFileDir, QObject *parent = 0);
	~ReadWorker();
	// 每个seriesUid 对应多个文件,
	static QMap< QString, QStringList> UID_Files;

	public slots:
	void checkDicomsFileDir(); // 检查文件夹下Dicom序列个数,应在单独的线程运行

signals:
	// 发送进度(0-100)
	void progress(int);
	
	// 线程结束信号
	void finish();

private:
	// 包含多个Dicom 单文件的文件夹,可能有多个序列。
	QString DicomsFileDir;
};
#include "ReadWorker.h"
#include "Image.h"

#include <QDir>

ReadWorker::ReadWorker(QString DicomsFileDir,QObject *parent)
	: QObject(parent)
{
	this->DicomsFileDir = DicomsFileDir;
}

ReadWorker::~ReadWorker()
{
}

QMap< QString, QStringList> ReadWorker::UID_Files;

void  ReadWorker::checkDicomsFileDir()
{
	// 清空序列
	UID_Files.clear();

	QDir dir(DicomsFileDir);
	// 获取文件夹下所有文件名
	QStringList files = dir.entryList(QDir::Files);
	int filesCount = files.count(); // 所有文件的个数

	Image *dicom = 0; // 单Dicom文件
	int progressValue = 0;
	
	// 遍历每个文件
	foreach(QString fileName, files)
	{
		++progressValue;
		emit progress(100 * progressValue / filesCount/* 转到0-100之间*/);

		// 带路径的文件名
		fileName = DicomsFileDir + "/" + fileName;

		//使用我们写的Image类读取dicom,此处使用了new,记住释放
		dicom = new Image(fileName);
		if (!dicom->isNormal())
		{			
			delete dicom; dicom = 0;
			continue; // 读取不成功(不是Dicom文件),跳出直接读取下一个文件
		}

		/*---读取成功,整理序列---*/
		QString temp = dicom->getSeriesUID(); // 获取该序列的 UID
		/*-----UID_Files键存在 序列号 temp 就把fileName添加到值------*/
		/*-----UID_Files键不存在 序列号 temp 就创建值,并插入键值---*/
		UID_Files.keys().contains(temp)? UID_Files[temp].append(fileName): UID_Files.insert(temp, QStringList(fileName));
		
		delete dicom; dicom = 0; // 操作完成后,释放,循环读取下一个。
	}

	emit finish();
}

四、编辑主界面DicomBrowse.h 和 DicomBrowse.cpp

DicomBrowse.h 中添加属性 bool isOpeing; // 是否正在读取文件 

...
class DicomBrowse : public QMainWindow
{
	...
public slots:
    ...
    void ReadCheckCompleted(); // worker完成后执行该函数
private:
	...
	bool isOpeing; // 是否正在读取文件
};

为了使QSettings 生效,编辑main.cpp 如下行

...
int main(int argc, char *argv[])
{
	QApplication a(argc, argv);
	a.setOrganizationName("CASMI");
	a.setOrganizationDomain("www.radiomics.net.cn");
	a.setApplicationName("DicomBrowse");
    ...
}

DicomBrowse.cpp 

...
#include "ReadWorker.h"

#include<QThread>
#include<QSettings>
#include <QFileDialog>
#include <QMessageBox>

DicomBrowse::DicomBrowse(QWidget *parent)
	: QMainWindow(parent)
{
	... 
	isOpeing = false; // 添加	
}
...
void DicomBrowse::on_pushButton_clicked()
{
	// 点击 "选择Dicom文件夹"按钮后,执行该函数
	QSettings s; // 为了记住上一次的路径
	QString dirStr = s.value("OPEN_FILEPATH", ".").toString();// 不存在的话为当前应用程序路径
	dirStr = QFileDialog::getExistingDirectory(this, QStringLiteral("选择Dicom序列所在的文件夹"), dirStr);

	if (dirStr.isEmpty())
		return;
	s.setValue("OPEN_FILEPATH", dirStr); // 记住该路径,以备下次使用
	

	if (isOpeing)
	{
		QMessageBox::warning(this, "TIP", QStringLiteral("正在检查数据,请等待完成打开其他数据!"));
		return;
	}

	isOpeing = true;
	ReadWorker *worker = new ReadWorker(dirStr);
	QThread *thread = new QThread();
	connect(thread, SIGNAL(started()), worker, SLOT(checkDicomsFileDir())); // 线程开始后执行worker->checkDicomsFileDir()
	connect(worker, SIGNAL(progress(int)), this, SLOT(setProgressBarValue(int)));// worker 发送信号,执行this->setProgressBarValue

	connect(worker, SIGNAL(finish()), this, SLOT(ReadCheckCompleted()));// 检查完成,执行this->ReadCheckCompleted()
	connect(worker, SIGNAL(finish()), worker, SLOT(deleteLater()));// 执行完成,析构worker
	connect(worker, SIGNAL(destroyed(QObject*)), thread, SLOT(quit()));// 析构worker 完成, 推出线程
	connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); // 推出线程, 析构线程
	worker->moveToThread(thread); // 把worker 移动到线程
	thread->start(); // 开始线程
}
...
void DicomBrowse::ReadCheckCompleted()
{
	ui.comboBox_which->clear();
     // worker->checkDicomsFileDir()线程执行完成后,执行该函数
	// 序列的个数
	int seriesCount = ReadWorker::UID_Files.count();
	
	ui.textBrowser->append(QStringLiteral("共有%1个序列: ").arg(seriesCount));

	foreach(QString uid, ReadWorker::UID_Files.keys())
	{
		ui.comboBox_which->addItem(uid);

		ui.textBrowser->append(QStringLiteral("序列%1: 共%2张图像").arg(uid).arg(ReadWorker::UID_Files[uid].count()));
	}

    isOpeing = false;
}
...

五 、 实验

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值