ITK读取多帧DICOM图像并显示图像

30 篇文章 1 订阅
7 篇文章 0 订阅
该代码示例展示了如何使用ITK和VTK库读取DICOM图像系列,并实现交互式滚动浏览。自定义的vtkInteractorStyleImage子类使得通过鼠标滚轮和键盘上下键可以改变切片。此外,代码还提取了DICOM图像的窗位和窗宽信息以调整显示。
摘要由CSDN通过智能技术生成

依赖:

ITK/4.13.2                                                                                      

VTK/8.2.0

代码:

#include <itkGDCMImageIO.h>
#include <itkGDCMSeriesFileNames.h>
#include <itkImageSeriesReader.h>
#include <itkImageToVTKImageFilter.h>
#include <vtkSmartPointer.h>
#include <vtkObjectFactory.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkActor.h>
#include <vtkImageViewer2.h>
#include <vtkDICOMImageReader.h>
#include <vtkImageData.h>
#include <vtkInteractorStyleImage.h>
#include <vtkActor2D.h>
#include <vtkTextProperty.h>
#include <vtkTextMapper.h>
#include <vtkImageFlip.h>
#include <vtkAutoInit.h>
#include <vector>

VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);


class  StatusMessage {
public:
    static std::string Format(int slice, int maxSlice) {
        std::stringstream tmp;
        tmp << "Slice Number " << slice + 1 << "/" << maxSlice + 1;
        return tmp.str();
    }

};

class myvtkInteractorStyleImage : public vtkInteractorStyleImage {
public:
    static myvtkInteractorStyleImage *New();
    vtkTypeMacro(myvtkInteractorStyleImage, vtkInteractorStyleImage);

protected:
    vtkImageViewer2 *_ImageViewer;
    vtkTextMapper *_StatusMapper;
    int _Slice;
    int _MinSlice;
    int _MaxSlice;

public:
    void SetImageViewer(vtkImageViewer2 *imageViewer) {
        _ImageViewer = imageViewer;
        _MinSlice = imageViewer->GetSliceMin();
        _MaxSlice = imageViewer->GetSliceMax();
        _Slice = _MinSlice;
        cout << "Slice: Min = " << _MinSlice << ", Max = " << _MaxSlice << endl;
    }

    void SetStatusMapper(vtkTextMapper *statusMapper) {
        _StatusMapper = statusMapper;
    }

protected:
    void MoveSliceForward() {
        if (_Slice < _MaxSlice) {
            _Slice += 1;
            cout << "MoveSliceForward::Slice = " << _Slice << endl;
            _ImageViewer->SetSlice(_Slice);
            std::string msg = StatusMessage::Format(_Slice, _MaxSlice);
            _StatusMapper->SetInput(msg.c_str());
            _ImageViewer->Render();
        }
    }

    void MoveSliceBackward() {
        if (_Slice > _MinSlice) {
            _Slice -= 1;
            cout << "MoveSliceBackward::Slice = " << _Slice << endl;
            _ImageViewer->SetSlice(_Slice);
            std::string msg = StatusMessage::Format(_Slice, _MaxSlice);
            _StatusMapper->SetInput(msg.c_str());
            _ImageViewer->Render();
        }
    }

    virtual void OnKeyDown() {
        std::string key = this->GetInteractor()->GetKeySym();
        if (key.compare("Up") == 0) {
            MoveSliceForward();
        }
        else if (key.compare("Down") == 0) {
            MoveSliceBackward();
        }

        vtkInteractorStyleImage::OnKeyDown();
    }

    virtual void OnMouseWheelForward() {
        MoveSliceForward();
    }

    virtual void OnMouseWheelBackward() {
        if (_Slice > _MinSlice) {
            MoveSliceBackward();
        }
    }
};

vtkStandardNewMacro(myvtkInteractorStyleImage);

std::vector<std::string> Split(const std::string& str, const std::string& pattern)
{
    //const char* convert to char*
    char* strc = new char[strlen(str.c_str()) + 1];
    strcpy(strc, str.c_str());
    std::vector<std::string> resultVec;
    char* tmpStr = strtok(strc, pattern.c_str());
    while (tmpStr != NULL)
    {
        resultVec.push_back(std::string(tmpStr));
        tmpStr = strtok(NULL, pattern.c_str());
    }

    delete[] strc;
    return resultVec;
}

std::string GetValuesByTag(itk::GDCMImageIO::Pointer dicomIO, const std::string& entryId)
{
    using Dictionary = itk::MetaDataDictionary;
    using MetaDataStringType = itk::MetaDataObject<std::string>;
    const Dictionary& dic = dicomIO->GetMetaDataDictionary();
    auto itr = dic.Begin();
    auto end = dic.End();
    //std::string entryId = "0010|0010";
    auto tagItr = dic.Find(entryId);
    std::string tagvalue("");
    if (tagItr != end)
    {
        MetaDataStringType::ConstPointer entryvalue =
            dynamic_cast<const MetaDataStringType*> (tagItr->second.GetPointer());
        if (entryvalue)
        {
            tagvalue = entryvalue->GetMetaDataObjectValue();
            std::cout << "tag: " << entryId << " value:" << tagvalue << std::endl;
        }
    }
    return tagvalue;
}

int main(int argc, char* argv[])
{
    if (argc < 2)
    {
        std::cerr << "Usage: " << argv[0] << " DicomDirectory" << std::endl;
        return EXIT_FAILURE;
    }

    using PixelType = signed short;
    constexpr unsigned int Dimension = 3; // The dimension is 3, not 2

    using ImageType = itk::Image<PixelType, Dimension>;

    using ImageIOType = itk::GDCMImageIO;
    ImageIOType::Pointer dicomIO = ImageIOType::New();

    using NamesGeneratorType = itk::GDCMSeriesFileNames;
    NamesGeneratorType::Pointer nameGenarator = NamesGeneratorType::New();
    nameGenarator->SetDirectory(argv[1]);

    using FilenamesContainer = std::vector<std::string>;
    FilenamesContainer filenames = nameGenarator->GetInputFileNames();

    using ReaderType = itk::ImageSeriesReader<ImageType>;
    ReaderType::Pointer reader = ReaderType::New();
    reader->SetImageIO(dicomIO);
    reader->SetFileNames(filenames);
    reader->SetReverseOrder(true);

    try
    {
        reader->Update();
    }
    catch (itk::ExceptionObject& ex)
    {
        std::cout << ex << std::endl;
        return EXIT_FAILURE;
    }

    char name[512];
    dicomIO->GetPatientName(name);
    std::cout << "patient: " << name << std::endl;

    //(0028, 1050) DS 40                                                # 1, 2 Window Center
    //(0028, 1051) DS 200                                               # 1, 4 Window Width
    std::string tagWindowCenter = "0028|1050";
    std::string valueWindowCenter = GetValuesByTag(dicomIO, tagWindowCenter);
    std::vector<std::string> WindowCenters = Split(valueWindowCenter, "\\");
    valueWindowCenter = WindowCenters.empty() ? "40" : WindowCenters[0];

    std::string tagWindowWidth = "0028|1051";
    std::string valueWindowWidth = GetValuesByTag(dicomIO, tagWindowWidth);
    std::vector<std::string> WindowWidths = Split(valueWindowWidth, "\\");
    valueWindowWidth = WindowWidths.empty() ? "400" : WindowWidths[0];

    using ImageConnector = itk::ImageToVTKImageFilter<ImageType>;
    ImageConnector::Pointer imageConnector = ImageConnector::New();
    imageConnector->SetInput(reader->GetOutput());
    imageConnector->Update();

    //===================================

     //flip image
    vtkSmartPointer<vtkImageFlip> flip = vtkSmartPointer<vtkImageFlip>::New();
    flip->SetInputData(imageConnector->GetOutput());
    flip->SetFilteredAxis(1);//y轴为1,x轴为0,z轴为2;
    flip->Update();

    vtkSmartPointer<vtkImageViewer2> imageViewer = vtkSmartPointer<vtkImageViewer2>::New();
    //imageViewer->SetInputConnection(reader->GetOutputPort());
    //imageViewer->SetInputData(imageConnector->GetOutput());
    imageViewer->SetInputData(flip->GetOutput());

    vtkSmartPointer<vtkTextProperty> sliceTextProp = vtkSmartPointer<vtkTextProperty>::New();
    sliceTextProp->SetFontFamilyToCourier();
    sliceTextProp->SetFontSize(20);
    sliceTextProp->SetVerticalJustificationToBottom();
    sliceTextProp->SetJustificationToLeft();

    vtkSmartPointer<vtkTextMapper> sliceTextMapper = vtkSmartPointer<vtkTextMapper>::New();
    std::string msg = StatusMessage::Format(imageViewer->GetSliceMin(), imageViewer->GetSliceMax());
    sliceTextMapper->SetInput(msg.c_str());
    sliceTextMapper->SetTextProperty(sliceTextProp);

    vtkSmartPointer<vtkActor2D> sliceTextActor = vtkSmartPointer<vtkActor2D>::New();
    sliceTextActor->SetMapper(sliceTextMapper);
    sliceTextActor->SetPosition(15, 10);

    vtkSmartPointer<vtkTextProperty> usageTextProp = vtkSmartPointer<vtkTextProperty>::New();
    usageTextProp->SetFontFamilyToCourier();
    usageTextProp->SetFontSize(14);
    usageTextProp->SetVerticalJustificationToTop();
    usageTextProp->SetJustificationToLeft();

    vtkSmartPointer<vtkTextMapper> usageTextMapper = vtkSmartPointer<vtkTextMapper>::New();
    usageTextMapper->SetInput("- Slice with mouse wheel\n  or Up/Down-Key\n- Zoom with pressed right\n  mouse button while dragging");
    usageTextMapper->SetTextProperty(usageTextProp);

    vtkSmartPointer<vtkActor2D> usageTextActor = vtkSmartPointer<vtkActor2D>::New();
    usageTextActor->SetMapper(usageTextMapper);
    usageTextActor->GetPositionCoordinate()->SetCoordinateSystemToNormalizedDisplay();
    usageTextActor->GetPositionCoordinate()->SetValue(0.05, 0.95);

    vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
        vtkSmartPointer<vtkRenderWindowInteractor>::New();

    vtkSmartPointer<myvtkInteractorStyleImage> myInteractorStyle =
        vtkSmartPointer<myvtkInteractorStyleImage>::New();

    myInteractorStyle->SetImageViewer(imageViewer);
    myInteractorStyle->SetStatusMapper(sliceTextMapper);

    imageViewer->SetupInteractor(renderWindowInteractor);
    renderWindowInteractor->SetInteractorStyle(myInteractorStyle);

    imageViewer->GetRenderer()->AddActor2D(sliceTextActor);
    imageViewer->GetRenderer()->AddActor2D(usageTextActor);

    imageViewer->GetRenderWindow()->SetSize(800, 600);
    imageViewer->SetColorLevel(atoi(valueWindowCenter.c_str()));//窗位   40 400
    imageViewer->SetColorWindow(atoi(valueWindowWidth.c_str()));//窗宽

    imageViewer->Render();
    imageViewer->GetRenderer()->ResetCamera();

    renderWindowInteractor->Start();

    return EXIT_SUCCESS;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值