QT C++ vtk 加载二维dicom 三维渲染 3DMPR

 

 

 

 

 

 

 

 

 

 

#include "widget3d.h"
#include "tabwidget.h"
#include <vtkRendererCollection.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <QKeyEvent>
#include <QtConcurrent/qtconcurrentrun.h>

asclepios::gui::Widget3D::Widget3D(QWidget* parent)
    : WidgetBase(parent)
{
    initData();
    initView();
    createConnections();
    m_tabWidget = parent;
}

//-----------------------------------------------------------------------------
void asclepios::gui::Widget3D::render()
{
    if (!m_image)
    {
        throw std::runtime_error("No image for widget 3d!");
    }
    try
    {
        m_toolbar->getUI().toolButtonCrop->setVisible(false);
        m_toolbar->getUI().comboBoxFilters->setVisible(false);
        startLoadingAnimation();
        m_vtkWidget->setImage(m_image);
        m_vtkWidget->setSeries(m_series);
        m_vtkWidget->setInteractor(m_qtvtkWidget->GetInteractor());
        m_future = QtConcurrent::run(onRenderAsync, this);
        Q_UNUSED(connect(this, &Widget3D::finishedRenderAsync,
            this, &Widget3D::onFinishedRenderAsync));
    }
    catch (const std::exception& ex)
    {
        //todo log
    }
}

//-----------------------------------------------------------------------------
bool asclepios::gui::Widget3D::eventFilter(QObject* watched, QEvent* event)
{
    if (event->type() == QEvent::KeyPress)
    {
        auto* const keyEvent = dynamic_cast<QKeyEvent*>(event);
        const int key = keyEvent->key();
        auto* const combo = m_toolbar->getUI().comboBoxFilters;
        switch (key)
        {
        case Qt::Key_Left:
        {
            const int currentIndex = combo->currentIndex();
            combo->setCurrentIndex(!combo->currentIndex()
                ? combo->count() - 1
                : currentIndex - 1);
            break;
        }
        case Qt::Key_Right:
        {
            const int currentIndex = combo->currentIndex();
            combo->setCurrentIndex(currentIndex == combo->count() - 1
                ? 0
                : currentIndex + 1);
            break;
        }
        default:
            break;
        }
    }
    return QWidget::eventFilter(watched, event);
}

//-----------------------------------------------------------------------------
void asclepios::gui::Widget3D::onfilterChanged(const QString& t_filter) const
{
    if (m_qtvtkWidget && m_vtkWidget)
    {
        m_vtkWidget->setFilter(t_filter);
        m_qtvtkWidget->GetRenderWindow()->Render();
    }
}

//-----------------------------------------------------------------------------
void asclepios::gui::Widget3D::onCropPressed(const bool& t_pressed) const
{
    m_vtkWidget->activateBoxWidget(t_pressed);
    m_qtvtkWidget->GetRenderWindow()->Render();
}

//-----------------------------------------------------------------------------
void asclepios::gui::Widget3D::onActivateWidget(const bool& t_flag)
{
    if (t_flag)
    {
        auto* event = new QFocusEvent(QEvent::FocusIn,
            Qt::FocusReason::MouseFocusReason);
        focusInEvent(event);
        delete event;
    }
}

//-----------------------------------------------------------------------------
void asclepios::gui::Widget3D::onSetMaximized() const
{
    if (m_tabWidget)
    {
        dynamic_cast<TabWidget*>
            (m_tabWidget)->onMaximize();
    }
}

//-----------------------------------------------------------------------------
void asclepios::gui::Widget3D::onFinishedRenderAsync()
{
    auto* const renderWindow =
        m_qtvtkWidget->GetRenderWindow();
    renderWindow->AddRenderer(m_vtkWidget->
        getRenderWindows()[0]->GetRenderers()->
        GetFirstRenderer());
    renderWindow->Render();
    onfilterChanged(m_toolbar->getUI()
        .comboBoxFilters->itemData(0).toString());
    stopLoadingAnimation();
    disconnect(this, &Widget3D::finishedRenderAsync,
        this, &Widget3D::onFinishedRenderAsync);
    m_toolbar->getUI().toolButtonCrop->setVisible(true);
    m_toolbar->getUI().comboBoxFilters->setVisible(true);
    installEventFilter(this);
}

//-----------------------------------------------------------------------------
void asclepios::gui::Widget3D::onRenderAsync(Widget3D* t_self)
{
    t_self->m_vtkWidget->render();
    emit t_self->finishedRenderAsync();
}

//-----------------------------------------------------------------------------
void asclepios::gui::Widget3D::initView()
{
    m_ui.setupUi(this);
    setAttribute(Qt::WA_DeleteOnClose);
    auto* const layout = new QVBoxLayout(this);
    layout->setSpacing(0);
    layout->setMargin(0);
    layout->addWidget(m_toolbar);
    layout->addWidget(m_qtvtkWidget);
    setLayout(layout);
}

//-----------------------------------------------------------------------------
void asclepios::gui::Widget3D::initData()
{
    m_qtvtkWidget = new QVTKOpenGLNativeWidget(this);
    m_qtvtkWidget->SetRenderWindow(vtkNew<vtkGenericOpenGLRenderWindow>());
    m_qtvtkWidget->GetRenderWindow()->SetDoubleBuffer(true);
    m_vtkWidget = std::make_unique<vtkWidget3D>();
    m_toolbar = new ToolbarWidget3D(this);
    m_vtkEvents = std::make_unique<vtkEventFilter>(this);
    setWidgetType(WidgetType::widget3d);
}

//-----------------------------------------------------------------------------
void asclepios::gui::Widget3D::createConnections()
{
    if (m_toolbar)
    {
        Q_UNUSED(connect(m_toolbar,
            &ToolbarWidget3D::filterChanged, this,
            &Widget3D::onfilterChanged));
        Q_UNUSED(connect(m_toolbar, &ToolbarWidget3D::cropPressed,
            this, &Widget3D::onCropPressed));
    }
    setFocusPolicy(Qt::FocusPolicy::WheelFocus);
    m_qtvtkWidget->installEventFilter(m_vtkEvents.get());
    Q_UNUSED(connect(m_vtkEvents.get(),
        &vtkEventFilter::activateWidget,
        this, &Widget3D::onActivateWidget));
    Q_UNUSED(connect(m_vtkEvents.get(),
        &vtkEventFilter::setMaximized,
        this, &Widget3D::onSetMaximized));
}

//-----------------------------------------------------------------------------
void asclepios::gui::Widget3D::startLoadingAnimation()
{
    m_loadingAnimation = std::make_unique<LoadingAnimation>(this);
    m_loadingAnimation->setWindowFlags(Qt::Widget);
    layout()->addWidget(m_loadingAnimation.get());
    m_loadingAnimation->show();
}

#include "vtkwidget3d.h"
#include <vtkRenderer.h>
#include <vtkDICOMMetaData.h>
#include <vtkWidgetRepresentation.h>
#include <vtkVolumeProperty.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkContourValues.h>
#include <QString>

void asclepios::gui::vtkWidget3D::initWidget()
{
    m_renderWindows[0] = vtkSmartPointer<vtkRenderWindow>::New();
    m_mapper = vtkSmartPointer<vtkSmartVolumeMapper>::New();
    m_renderer = vtkSmartPointer<vtkRenderer>::New();
    m_volume = vtkSmartPointer<vtkVolume>::New();
    m_transferFunction = std::make_unique<TransferFunction>();
}

//-----------------------------------------------------------------------------
void asclepios::gui::vtkWidget3D::initBoxWidget()
{
    if (!m_renderer || !m_volume)
    {
        return;
    }
    m_boxWidget = vtkSmartPointer<vtkBoxWidget2>::New();
    m_boxWidget->SetInteractor(m_renderer->GetRenderWindow()->GetInteractor());
    m_boxWidget->CreateDefaultRepresentation();
    m_boxWidget->GetRepresentation()->SetPlaceFactor(1);
    m_boxWidget->GetRepresentation()->PlaceWidget(m_volume->GetBounds());
    initBoxWidgetCallback();
}

//-----------------------------------------------------------------------------
void asclepios::gui::vtkWidget3D::initBoxWidgetCallback()
{
    m_boxWidgetCallback = vtkSmartPointer<vtkBoxWidget3DCallback>::New();
    m_boxWidgetCallback->setVolume(m_volume);
    m_boxWidget->AddObserver(vtkCommand::InteractionEvent, m_boxWidgetCallback);
}

//-----------------------------------------------------------------------------
void asclepios::gui::vtkWidget3D::initInteractorStyle()
{
    m_interactorStyle =
        vtkSmartPointer<vtkWidget3DInteractorStyle>::New();
    m_interactorStyle->setWidget(this);
    m_interactorStyle->setTransferFunction(m_transferFunction.get());
    m_interactor->SetInteractorStyle(m_interactorStyle);
}

//-----------------------------------------------------------------------------
void asclepios::gui::vtkWidget3D::setVolumeMapperBlend() const
{
    m_mapper->SetBlendMode(vtkVolumeMapper::COMPOSITE_BLEND);
}

//-----------------------------------------------------------------------------
std::tuple<int, int> asclepios::gui::vtkWidget3D::getWindowLevel() const
{
    const auto imageReader =
        m_image->getImageReader();
    return std::make_tuple<int, int>(imageReader->
                                     GetMetaData()->Get(DC::WindowCenter).AsInt(),
                                     imageReader->GetMetaData()->Get(DC::WindowWidth).AsInt());
}

//-----------------------------------------------------------------------------
void asclepios::gui::vtkWidget3D::setFilter(const QString& t_filePath) 
{
    try
    {
        if (t_filePath == "MIP")
        {
            m_transferFunction.reset();
            m_transferFunction = std::make_unique<TransferFunction>();
            m_mapper->SetBlendMode(vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND);
            m_transferFunction->setMaximumIntensityProjectionFunction(0, 0);
            const auto [window, level] = getWindowLevel();
            m_transferFunction->updateWindowLevel(window, level);
        }
        else
        {
            m_mapper->SetBlendMode(vtkVolumeMapper::COMPOSITE_BLEND);
            m_transferFunction->loadFilterFromFile(t_filePath);
        }
        updateFilter();
        m_interactorStyle->setTransferFunction(m_transferFunction.get());
        
    }
    catch (const std::exception& ex)
    {
        //todo log
    }
}

//-----------------------------------------------------------------------------
void asclepios::gui::vtkWidget3D::render()
{
    m_renderWindows[0]->OffScreenRenderingOn();
    setVolumeMapperBlend();
    const auto [window, level] = getWindowLevel();
    const auto reader = m_image && m_image->getIsMultiFrame()
                            ? m_image->getImageReader()
                            : m_series->getReaderForAllSingleFrameImages();
    m_mapper->SetInputConnection(reader->GetOutputPort());
    m_transferFunction->updateWindowLevel(window, level);
    m_volume->SetMapper(m_mapper);
    m_renderer->AddActor(m_volume);
    m_renderWindows[0]->AddRenderer(m_renderer);
    m_renderWindows[0]->Render();
    m_renderWindows[0]->OffScreenRenderingOff();
    auto* const extend = m_volume->GetBounds();
    m_volume->SetOrigin(extend[0] + (extend[1] - extend[0]) / 2,
                        extend[2] + (extend[3] - extend[2]) / 2, 0);
    initInteractorStyle();
}

//-----------------------------------------------------------------------------
void asclepios::gui::vtkWidget3D::activateBoxWidget(const bool& t_flag)
{
    if (!m_boxWidget)
    {
        initBoxWidget();
    }
    m_boxWidget->SetEnabled(t_flag);
}

//-----------------------------------------------------------------------------
void asclepios::gui::vtkWidget3D::updateFilter() const
{
    m_volume->GetProperty()->SetInterpolationTypeToLinear();
    m_volume->GetProperty()->SetScalarOpacity(m_transferFunction->getOpacityFunction());
    m_volume->GetProperty()->SetAmbient(m_transferFunction->getAmbient());
    m_volume->GetProperty()->SetColor(m_transferFunction->getColorFunction());
    m_volume->GetProperty()->SetDiffuse(m_transferFunction->getDiffuse());
    m_volume->GetProperty()->SetSpecular(m_transferFunction->getSpecular());
    m_volume->GetProperty()->SetSpecularPower(m_transferFunction->getSpecularPower());
    m_volume->GetProperty()->GetIsoSurfaceValues()->SetValue(0, 0);
    (m_transferFunction->getHasShade()) ? m_volume->GetProperty()->ShadeOn() : m_volume->GetProperty()->ShadeOff();
}
{
  "name":"Dark Bone",
  "color": [
    {
      "value": 46.733612060546875,
      "red": 0.0,
      "green": 0.0,
      "blue": 0.0
    },
    {
      "value": 134.97621154785156,
      "red": 1,
      "green": 1,
      "blue": 1
    },
    {
      "value": 244.72689819335938,
      "red": 0.20000000298023224,
      "green": 0.20000000298023224,
      "blue": 0.20000000298023224
    },
    {
      "value": -812.04962158203125,
      "red": 0.0,
      "green": 1,
      "blue": 1
    },
    {
      "value": -622.0498046875,
      "red": 0.0,
      "green": 1,
      "blue": 1
    },
    {
      "value": -420.04998779296875,
      "red": 0.0,
      "green": 1,
      "blue":  1
    },
    {
      "value": -262.84738159179688,
      "red": 0,
      "green": 1,
      "blue": 1
    }
  ],
  "opacity": [
    {
      "value": 46.733612060546875,
      "alpha": 0.0
    },
    {
      "value": 134.97621154785156,
      "alpha": 0.25999999046325684
    },
    {
      "value": 244.72689819335938,
      "alpha": 0.5300024151802063
    },
    {
      "value": -812.04962158203125,
      "alpha": 0.0
    },
    {
      "value": -622.0498046875,
      "alpha": 0.1643165796995163
    },
    {
      "value": -420.04998779296875,
      "alpha": 0.36469146609306335
    },
    {
      "value": -262.84738159179688,
      "alpha": 0.0
    }
  ],
  "ambient":
    {
      "value": 0.4
    },
  "diffuse":
    {
      "value": 0.7
    },
  "specular":
    {
      "value": 1.0
    },
  "specularpower":
    {
      "value": 64
    },
  "shade":
    {
      "value": 1
    }
}

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

灿烂李

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值