我的程序使用VTK和QT在QT窗口中创建DICOM查看器。我正在尝试设置一个自定义的交互器,以便可以覆盖输入功能。创建此自定义交互器类后,我遇到了链接器错误。我的代码如下:

FluoroViewer.h:

#ifndef FluoroViewer_H
#define FluoroViewer_H

#include <QMainWindow>

#include <vtkSmartPointer.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkDICOMImageReader.h>
#include <vtkImageViewer2.h>

#include "InteractorStyleImage.h"

namespace Ui {
    class FluoroViewer;
}

class FluoroViewer : public QMainWindow {
    Q_OBJECT

    public:
        explicit FluoroViewer(QWidget *parent = 0);
        ~FluoroViewer();

    private slots:
        void openDICOMFolder();
        void on_loadImages_clicked();

    private:
        Ui::FluoroViewer *ui;
        void drawDICOMSeries(std::string folderDICOM);
        vtkSmartPointer<vtkDICOMImageReader> readerDICOMSeries;
        vtkSmartPointer<vtkImageViewer2> imageViewerDICOMSeries;
        vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor;
        vtkSmartPointer<InteractorStyleImage> interactorStyle;
};

#endif


FluoroViewer.cxx:

#include "FluoroViewer.h"
#include "ui_FluoroViewer.h"

#include <QFileDialog>

FluoroViewer::FluoroViewer(QWidget *parent) : QMainWindow(parent), ui(new Ui::FluoroViewer) {
    ui->setupUi(this);
    readerDICOMSeries = vtkSmartPointer<vtkDICOMImageReader>::New();
    imageViewerDICOMSeries = vtkSmartPointer<vtkImageViewer2>::New();
    renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
    //interactorStyle = vtkSmartPointer<InteractorStyleImage>::New();
}

FluoroViewer::~FluoroViewer() {
    delete ui;
}

void FluoroViewer::openDICOMFolder() {
    QString folderNameDICOM = QFileDialog::getExistingDirectory(this, tr("Open DICOM Folder"), QDir::currentPath(), QFileDialog::ShowDirsOnly);
    std::string folderName = folderNameDICOM.toUtf8().constData();
    drawDICOMSeries(folderName);
}

void FluoroViewer::drawDICOMSeries(std::string folderDICOM) {
    readerDICOMSeries->SetDirectoryName(folderDICOM.c_str());
    readerDICOMSeries->Update();

    imageViewerDICOMSeries->SetInputConnection(readerDICOMSeries->GetOutputPort());

    ui->slider->setMinimum(imageViewerDICOMSeries->GetSliceMin());
    ui->slider->setMaximum(imageViewerDICOMSeries->GetSliceMax());

    //interactorStyle->SetImageViewer(imageViewerDICOMSeries);

    imageViewerDICOMSeries->SetupInteractor(renderWindowInteractor);
    //renderWindowInteractor->SetInteractorStyle(interactorStyle);

    // SET FLUORO COLOR AND WINDOW LEVELS
    imageViewerDICOMSeries->SetColorLevel(523);
    imageViewerDICOMSeries->SetColorWindow(-1223);

    imageViewerDICOMSeries->SetRenderWindow(ui->vtkRenderer->GetRenderWindow());
    imageViewerDICOMSeries->Render();
    renderWindowInteractor->Disable();
    renderWindowInteractor->Start();
}

void FluoroViewer::on_loadImages_clicked() {
    openDICOMFolder();
}


InteractorStyleImage.h:

#ifndef InteractorStyleImage_H
#define InteractorStyleImage_H

#include <vtkSmartPointer.h>
#include <vtkObjectFactory.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkImageViewer2.h>
#include <vtkDICOMImageReader.h>
#include <vtkInteractorStyleImage.h>

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

    protected:
        vtkImageViewer2* imageViewer;
        int currentSlice;
        int minSlice;
        int maxSlice;

    public:
        void SetImageViewer(vtkImageViewer2* imageViewerTemp);
        void MoveSliceForward();
        void MoveSliceBackward();

    public:
        virtual void OnKeyDown() {
            std::string key = this->GetInteractor()->GetKeySym();
            if (key.compare("Up") == 0) {
                cout << "Up arrow key was pressed." << endl;
                MoveSliceForward();
            }
            else if (key.compare("Down") == 0) {
                cout << "Down arrow key was pressed." << endl;
                MoveSliceBackward();
            }
            vtkInteractorStyleImage::OnKeyDown();
        }

    public:
        virtual void OnMouseWheelForward() {
            cout << "Scrolled mouse wheel forward." << endl;
            MoveSliceForward();
            //vtkInteractorStyleImage::OnMouseWheelForward();
        }

    public:
        virtual void OnMouseWheelBackward() {
            cout << "Scrolled mouse wheel backward." << endl;
            if (currentSlice > minSlice) {
                MoveSliceBackward();
            }
            //vtkInteractorStyleImage::OnMouseWheelBackward();
        }
};
vtkStandardNewMacro(InteractorStyleImage);

#endif


InteractorStyleImage.cxx:

#include "InteractorStyleImage.h"

void InteractorStyleImage::SetImageViewer(vtkImageViewer2* imageViewerTemp) {
    imageViewer = imageViewerTemp;
    minSlice = imageViewer->GetSliceMin();
    maxSlice = imageViewer->GetSliceMax();
    currentSlice = minSlice;
    cout << "Slicer: Min = " << minSlice << ", Max = " << maxSlice;
}

void InteractorStyleImage::MoveSliceForward() {
    if(currentSlice < maxSlice) {
        currentSlice += 1;
        imageViewer->SetSlice(currentSlice);
        imageViewer->Render();
    }
}

void InteractorStyleImage::MoveSliceBackward() {
    if(currentSlice > minSlice) {
        currentSlice -= 1;
        imageViewer->SetSlice(currentSlice);
        imageViewer->Render();
    }
}


FluoroViewerDriver.cxx:

#include <QApplication>
#include "FluoroViewer.h"

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    FluoroViewer fluoroViewer;
    fluoroViewer.show();

    return app.exec();
}


关于这个问题有什么想法吗?

最佳答案

这很可能是由于vtkStandardNewMacro()引起的。
您没有显示如何构建该程序,但是我很确定FluoroViewer最终会出现在一个翻译单元中,而InteractorStyleImage会出现在另一个翻译单元中。但是,FluoroViewer #includes InteractorStyleImage.h,它定义了New函数。因此,您最终将在两个单独的对象中使用两个相同的符号,并且链接器会出现错误。解决方案是将vtkStandardNewMacro()调用行移至实现(* .cpp文件)中。

HTH,

米罗

07-28 08:44