由于mitk.net被人恶意抢注, 中科院分子影像重点实验室的www.mitk.net 改到 www.mitk.net.cn 。
目录:
第一章 《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 图像浏览器---收尾》
一、设计视图类DicomView
1) 在项目上右键->添加->Add Qt Class , 按照向导添加类 DicomView,如下图
2) DicomView类继承 QGraphicsView,构造标签为QWidget *parent,如下图
3) 编辑DicomView.h 和 cpp
#pragma once
#include <QGraphicsView>
#include "SeriesBase.h"
class QGraphicsScene;
class QGraphicsPixmapItem;
class QGraphicsWidget;
class DicomView : public QGraphicsView
{
Q_OBJECT
public:
enum viewStatus {
Browse,
Zoom,//缩放
Pan, // 移动
Magnifier, // 放大镜
Drawing,// 画
};
DicomView(QWidget *parent=0);
~DicomView();
void setSeries(SeriesBase*series);
void resizePixmapItem(); // 窗口改变时
void repositionAuxItems(); // 窗口改变时
void updateView();
void setHighlight(bool yes); // 边框
public slots:
void setCurFrameItem(int);
signals:
void windowChanged();// 窗宽位改变信号
void clicked(SeriesBase::ViewType);// 点击
protected:
void mousePressEvent(QMouseEvent *event); // 鼠标按住时触发
void mouseMoveEvent(QMouseEvent *event); // 鼠标移动时触发
void mouseReleaseEvent(QMouseEvent *event); // 鼠标释放后触发
void wheelEvent(QWheelEvent *e); // 滚轮出发
void resizeEvent(QResizeEvent *event); // 窗口调整时运行
QSize sizeHint() const { return hintSize; }
private:
QGraphicsScene *scene;// 场景
QGraphicsPixmapItem *pixmapItem;//图像项 场景中的图像
QGraphicsSimpleTextItem *posValueItem;// 文本项 显示当前鼠标值
QGraphicsSimpleTextItem *curFrameItem; // 文本项 显示当前帧
QGraphicsWidget *slider;// 控制条
SeriesBase *dicoms; // 该视图显示的数据
QSize hintSize;
double factor;
double fixFactor;// xspace/yspace 宽高的比例
QPoint prevMousePos; //
viewStatus status;
};
#include "DicomView.h"
#include <QGraphicsPixmapItem>
#include <QGraphicsWidget>
#include <QGraphicsProxyWidget>
#include <QGraphicsLinearLayout>
#include <QMouseEvent>
#include <qslider.h>
DicomView::DicomView(QWidget *parent)
: QGraphicsView(parent)
{
scene = new QGraphicsScene(this);
pixmapItem = new QGraphicsPixmapItem;
posValueItem = new QGraphicsSimpleTextItem;
curFrameItem = new QGraphicsSimpleTextItem;
dicoms = 0;
status = Browse;
setFocusPolicy(Qt::StrongFocus);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setContextMenuPolicy(Qt::DefaultContextMenu);
setBackgroundBrush(QBrush(Qt::black));
setAcceptDrops(true);
setFrameShape(QFrame::Box);
setFrameShadow(QFrame::Plain);
setAlignment(Qt::AlignCenter);
setResizeAnchor(QGraphicsView::AnchorViewCenter);
setHighlight(false);
scene->setSceneRect(-5000, -5000, 10000, 10000);
setScene(scene);
// 图片切换风格
pixmapItem->setTransformationMode(Qt::SmoothTransformation);
pixmapItem->setAcceptHoverEvents(true);
posValueItem->setBrush(Qt::magenta);
curFrameItem->setBrush(Qt::magenta);
scene->addItem(pixmapItem);
scene->addItem(posValueItem);
scene->addItem(curFrameItem);
slider = new QGraphicsWidget;
QGraphicsLinearLayout *verticalLayout = new QGraphicsLinearLayout;
verticalLayout->setOrientation(Qt::Vertical);
verticalLayout->setSpacing(0);
slider->setLayout(verticalLayout);
scene->addItem(slider);
}
DicomView::~DicomView()
{
}
void DicomView::setSeries(SeriesBase * series)
{
if (!series)
return;
if (!series->isNormal())
return;
if (dicoms == 0)
{
// 把dicoms->slider 添加到 slider
QGraphicsProxyWidget*pw = scene->addWidget(series->slider);
QGraphicsLinearLayout *verticalLayout = (QGraphicsLinearLayout *)slider->layout();
verticalLayout->addItem(pw);
}
this->dicoms = series;
dicoms->setDefaultWindow();
emit windowChanged();
dicoms->gotoFrame(dicoms->getFrameCount() / 2);
connect(dicoms->slider, SIGNAL(valueChanged(int)), this, SLOT(setCurFrameItem(int)));
double xSpacing = 0, ySpacing = 0;
if (dicoms->getPixSpacing(xSpacing, ySpacing)) {
if (xSpacing > 0.000001 && ySpacing > 0.000001) {
double psX = xSpacing;
double psY = ySpacing;
fixFactor = psY / psX;
}
}
pixmapItem->setPos(0, 0);
pixmapItem->setRotation(0);
pixmapItem->resetTransform();
updateView();
scene->update(scene->sceneRect());
}
void DicomView::resizePixmapItem()
{
if (!pixmapItem->pixmap().isNull()) {
QRectF pixmapRect = pixmapItem->boundingRect();
QRectF viewRect = this->rect();
//if (!manualZoom) {
if (pixmapRect.width()*viewRect.height() < pixmapRect.height()*fixFactor*viewRect.width())
factor = viewRect.height() / (pixmapRect.height()*fixFactor);
else
factor = viewRect.width() / pixmapRect.width();
//}
pixmapItem->setTransform(QTransform(factor, 0, 0, factor*fixFactor, 0, 0));
// if (!manualPan)
centerOn(pixmapItem);
}
}
void DicomView::repositionAuxItems()
{
QPointF sceneTL = mapToScene(rect().topLeft());
QPointF sceneBR = mapToScene(rect().bottomRight());
curFrameItem->setPos(sceneBR.x() - 68, sceneTL.y()+18);
slider->setPos(sceneBR.x() - 58, sceneTL.y() + 58);
QSizeF slider_size(58, sceneBR.y() - sceneTL.y() - 116);
slider->resize(slider_size);
posValueItem->setPos(sceneTL.x()+ 10, sceneBR.y()- 58);
}
void DicomView::updateView()
{
QPixmap pixmap;
if (dicoms&&dicoms->isNormal()) {
dicoms->getPixmap(pixmap);
pixmapItem->setPixmap(pixmap);
pixmapItem->setTransformOriginPoint(pixmapItem->boundingRect().center());
}
else {
pixmapItem->setPixmap(pixmap);
curFrameItem->setText("");
posValueItem->setText("");
}
resizePixmapItem();
repositionAuxItems();
}
void DicomView::setHighlight(bool yes)
{
}
void DicomView::setCurFrameItem(int)
{
if (!dicoms || !dicoms->isNormal())
return;
curFrameItem->setText(tr("%1-%2").arg(dicoms->getCurFrame()).arg(dicoms->getFrameCount()));
}
void DicomView::mousePressEvent(QMouseEvent * event)
{
if (dicoms&&dicoms->isNormal())
{
emit clicked(dicoms->getViewType());
QPointF sp = mapToScene(event->pos());
QPointF ip = pixmapItem->mapFromScene(sp);
prevMousePos = event->pos();
if (event->button() == Qt::LeftButton) {
setDragMode(QGraphicsView::NoDrag);
switch (status) {
case Browse:
if (!(event->modifiers()&Qt::ControlModifier)) {
setDragMode(QGraphicsView::RubberBandDrag);
setCursor(Qt::ArrowCursor); // 划框
}
break;
}
}
QGraphicsView::mousePressEvent(event);
}
}
void DicomView::mouseMoveEvent(QMouseEvent * event)
{
if (dicoms&&dicoms->isNormal()) {
QPointF sp = mapToScene(event->pos());
QPointF ip = pixmapItem->mapFromScene(sp);
if (pixmapItem->contains(ip)) {
QPoint pos = ip.toPoint();
QString s = dicoms->getPixelValue(pos.x(), pos.y());
posValueItem->setText(tr("(%1, %2):").arg(pos.x()).arg(pos.y())+ s);
}
}
// 按住右键调整窗宽窗位
if (event->buttons()&Qt::RightButton) {
// 调整窗宽位
setDragMode(QGraphicsView::NoDrag);
setCursor(Qt::ArrowCursor);
QPoint delta = event->pos() - prevMousePos;
dicoms->setWindowDelta(-delta.y() * 16, delta.x() * 16);
emit windowChanged();
updateView();
}
QGraphicsView::mouseMoveEvent(event);
}
void DicomView::mouseReleaseEvent(QMouseEvent * event)
{
if (dicoms&&dicoms->isNormal()) {
if (event->button() == Qt::LeftButton) {
switch (status) {
case Browse:
// 划框时结束时调整窗宽窗位
if (scene->selectedItems().size() == 0)
{
if (rubberBandRect().isValid())
{
if (dicoms->getViewType() == SeriesBase::XY)
{
dicoms->setRoiWindow(pixmapItem->mapFromScene(mapToScene(rubberBandRect())).boundingRect());
emit windowChanged();
updateView();
}
}
}
break;
}
}
}
QGraphicsView::mouseReleaseEvent(event);
}
void DicomView::wheelEvent(QWheelEvent * e)
{
QPoint delta = e->angleDelta();
if (dicoms == 0 || !dicoms->isNormal()) return;
if (delta.y() > 0) dicoms->prevFrame();
else if (delta.y() < 0) dicoms->nextFrame();
updateView();
}
void DicomView::resizeEvent(QResizeEvent * event)
{
resizePixmapItem();
repositionAuxItems();
}
二、提升UI文件QGraphicsView 为 DicomView
保存提升后的ui,运行调试,就会发现显示框变黑了,提升成功。
三、实验“选择序列”下拉菜单功能
...
class SeriesBase; // 添加
class DicomBrowse : public QMainWindow
{
...
public slots:
...
void on_windowChanged();
private:
...
SeriesBase *xyS;// 添加 xy视图的序列
SeriesBase *xzS;// 添加
SeriesBase *yzS;// 添加
}
...
#include "SeriesBase.h" // 添加
#include "XYSeries.h"
#include "XZSeries.h"
#include "YZSeries.h"
...
DicomBrowse::DicomBrowse(QWidget *parent)
: QMainWindow(parent)
{
...
connect(ui.graphicsView_XY, SIGNAL(windowChanged()), this, SLOT(on_windowChanged()));
xyS = new XYSeries(); // 添加
xzS = new XZSeries();
yzS = new YZSeries();
}
DicomBrowse::~DicomBrowse()
{
delete xyS;
delete xzS;
delete yzS;
}
...
// 点击“选择序列”下拉菜单后执行
void DicomBrowse::on_comboBox_which_currentIndexChanged(QString seriesUID)
{
if (isOpeing)
return;
isOpeing = true;
SeriesBase::readSeriesUid(seriesUID); // 读取序列
isOpeing = false;
if (!SeriesBase::isNormal())
return;
ui.textBrowser->clear();
// ui.textBrowser->append(QStringLiteral("共有%1个序列>>").arg(ReadWorker::UID_Files.count()));
ui.textBrowser->append(QStringLiteral("当前序列(%1):").arg(seriesUID));
int w, h, s;
SeriesBase::getSeriesSize(w, h, s);
ui.textBrowser->append(QStringLiteral("宽:%1").arg(w));
ui.textBrowser->append(QStringLiteral("高:%1").arg(h));
ui.textBrowser->append(QStringLiteral("图像数:%1").arg(s));
xyS->update(); xzS->update(); yzS->update();
ui.graphicsView_XY->setSeries(xyS);
}
...
void DicomBrowse::on_comboBox_currentIndexChanged(int color)
{
// 伪彩下拉菜单选择彩色后,设置序列彩色,并更新视图
SeriesBase::setColor(color);
ui.graphicsView_XY->updateView();
}
...
void DicomBrowse::on_lineEdit_ww_textEdited(QString ww)
{
// 窗宽编辑框数字编辑完成后,设置序列窗宽位,并更新视图
double ww_d = 0.0, wl = 0.0;
SeriesBase::getWindow(wl, ww_d);
ww_d = ww.toDouble();
SeriesBase::setWindow(wl, ww_d);
ui.graphicsView_XY->updateView();
}
void DicomBrowse::on_lineEdit_wl_textEdited(QString wl)
{
// 窗位编辑框数字编辑完成后,设置序列窗宽位,并更新视图
double ww = 0.0, wl_d = 0.0;
SeriesBase::getWindow(wl_d, ww);
wl_d = wl.toDouble();
SeriesBase::setWindow(wl_d, ww);
ui.graphicsView_XY->updateView();
}
void DicomBrowse::on_windowChanged()
{
// 更新窗宽、窗位的编辑框数字
double ww = 0.0, wl = 0.0;
SeriesBase::getWindow(wl, ww);
set_lineEdit_wl_text(wl);
set_lineEdit_ww_text(ww);
}
// 修改该函数
void DicomBrowse::ReadCheckCompleted()
{
...
on_comboBox_which_currentIndexChanged(ui.comboBox_which->currentText());
}
...