Skip to content

调试时随时浏览模型、图像

平时使用vtk时候,如果需要经常看当前计算效果,可以用下这个类。支持vtkPolyData、vtkImageData自动在需要的地方显示,支持自定义颜色(vtkUnsignedCharArray需要传入)。

使用方法:在需要的计算 cpp 里引入 #include "vtkutil.h",计算中需要显示步骤,把 data 直接放到 ShowVtkDebugPolydata 里,程序执行到这里会自动断点,弹出当前计算结果,关闭弹窗后程序接着运行。保存数据的话这里只留了个 vtp 的输出(计算中间量,带各种信息)。

举列,下面这个提取中心线的程序。每计算一部,用一次 ShowVtkDebugPolydata,可以看到当前结果,确认才计算下一步。

    // 0 显示结果  输入
    VtkUtil::ShowVtkDebugPolydata(surface);
    // 1 计算  压缩模型
    vtkNew<vtkDecimatePro> decimation;
    decimation->SetInputConnection(surface);
    decimation->SetTargetReduction(0.9);
    decimation->Update();
    // 1 显示结果 压缩模型
    VtkUtil::ShowVtkDebugPolydata(decimation->GetOutput);
    // 2 计算  表面整理
    vtkNew<vtkCleanPolyData> surface_cleaner;
    surface_cleaner->SetInputData(decimation->GetOutput);
    surface_cleaner->Update();
    // 2 显示结果  表面整理 
    VtkUtil::ShowVtkDebugPolydata(surface_cleaner->GetOutput);
    // 3 计算  三角形相交检查
    vtkNew<vtkTriangleFilter> surface_triangulator;
    surface_triangulator->SetInputConnection(surface_cleaner->GetOutputPort());
    surface_triangulator->PassLinesOff();
    surface_triangulator->PassVertsOff();
    surface_triangulator->Update();
    vtkSmartPointer<vtkPolyData> centerline_input_surface =
    surface_triangulator->GetOutput();
    vtkSmartPointer<vtkIdList> cap_center_ids = nullptr;
    vtkSmartPointer<vtkvmtkCapPolyData> surface_capper;
    // 3 显示结果  表面整理 
    VtkUtil::ShowVtkDebugPolydata(surface_capper->GetOutput);
    // 4 计算  表面封闭
    surface_capper = vtkSmartPointer<vtkvmtkCapPolyData>::New();
    surface_capper->SetInputConnection(surface_triangulator->GetOutputPort());
    surface_capper->SetDisplacement(0);
    surface_capper->SetInPlaneDisplacement(0);
    surface_capper->Update();
    centerline_input_surface = surface_capper->GetOutput();
    cap_center_ids = surface_capper->GetCapCenterIds();
    vtkNew<vtkIdList> inlet_seed_ids, outlet_seed_ids;
    inlet_seed_ids->InsertNextId(0);
    outlet_seed_ids->InsertNextId(cap_center_ids->GetNumberOfIds() - 1);
    // 4 显示结果  表面封闭
    VtkUtil::ShowVtkDebugPolydata(centerline_input_surface);
    // 5 计算  计算中心线
    vtkNew<vtkvmtkPolyDataCenterlines> centerline_filter;
    centerline_filter->SetInputData(centerline_input_surface);
    centerline_filter->SetCapCenterIds(cap_center_ids);
    centerline_filter->SetSourceSeedIds(inlet_seed_ids);
    centerline_filter->SetTargetSeedIds(outlet_seed_ids);
    centerline_filter->SetRadiusArrayName("MaximumInscribedSphereRadius");
    centerline_filter->SetCostFunction("1/R");
    centerline_filter->SetFlipNormals(0);
    centerline_filter->SetAppendEndPointsToCenterlines(0);
    centerline_filter->SetSimplifyVoronoi(0);
    centerline_filter->SetCenterlineResampling(0);
    centerline_filter->SetResamplingStepLength(1.0);
    centerline_filter->Update();
    // 5 显示结果  计算中心线
    VtkUtil::ShowVtkDebugPolydata(centerline_filter->Update());
    return centerline_filter->GetOutput();
#ifndef VTKUTIL_H
#define VTKUTIL_H

#include <QImage>
#include <vtkPolyData.h>
#include <vtkImageData.h>
#include <vtkSmartPointer.h>

class VtkUtil {
  public:
    /*!
     * @brief VtkImageDataToQImage 屏幕图片截取
     */
    static QImage VtkImageDataToQImage(
        vtkSmartPointer<vtkImageData> imageData, const qint32 value = 0);

    /*!
     * @brief ShowVtkDebugPolydata 调试时可以临时显示vtk数据
     */
    static void ShowVtkDebugPolydata(vtkSmartPointer<vtkPolyData> surface);
    static void ShowVtkDebugPolydata(vtkSmartPointer<vtkPolyData> surface,
                                     QList<quint32> self_intersected_list);
    static void ShowVtkDebugPolydata(vtkSmartPointer<vtkImageData> surface);

    /*!
     * @brief WriteVTP 调试时保存出vtp数据
     */
    static void WriteVTP(vtkSmartPointer<vtkPolyData> surface,
                         QString filename = "tmp.vtp");

};

#endif // VTKUTIL_H
#include "vtkutil.h"
#include <QDebug>

// vtk include
#include <vtkActor.h>
#include <vtkCellData.h>
#include <vtkRenderer.h>
#include <vtkImageViewer2.h>
#include <vtkRenderWindow.h>
#include <vtkPolyDataMapper.h>
#include <vtkXMLPolyDataWriter.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleTrackballCamera.h>

#define ISDEBUGGING 0

QImage VtkUtil::VtkImageDataToQImage(
    vtkSmartPointer<vtkImageData> imageData, const qint32 value) {
    if (!imageData) {
        qWarning() << "image data is null";
        return QImage();
    }
    /// \todo retrieve just the UpdateExtent
    qint32 width = imageData->GetDimensions()[0];
    qint32 height = imageData->GetDimensions()[1];
    QImage image(width, height, QImage::Format_RGB32);
    QRgb *rgbPtr = reinterpret_cast<QRgb *>(image.bits()) + width * (height - 1);
    unsigned char *colorsPtr =
        reinterpret_cast<unsigned char *>(imageData->GetScalarPointer());

    // Loop over the vtkImageData contents.
    for (qint32 row = 0; row < height; row++) {
        for (qint32 col = 0; col < width; col++) {
            // Swap the vtkImageData RGB values with an equivalent QColor
            *(rgbPtr++) = QColor(colorsPtr[0], colorsPtr[1], colorsPtr[2]).rgb();
            colorsPtr += imageData->GetNumberOfScalarComponents();
        }

        rgbPtr -= width * 2;
    }
    if(1 == value) {
        image = image.copy((image.width() - image.height()) / 2, 0,
                           image.height(), image.height());
    } else if(2 == value) {
        image = image.scaled(image.width(), image.width());
    }
    return image;
}

void VtkUtil::ShowVtkDebugPolydata(vtkSmartPointer<vtkPolyData> surface) {
#if ISDEBUGGING
    vtkNew<vtkPolyDataMapper> polydatamapper ;
    polydatamapper->SetInputData(surface);
    vtkNew<vtkActor> actor ;
    actor->SetMapper(polydatamapper);
    // actor->GetProperty()->SetOpacity(0.1);
    vtkNew<vtkRenderer> renderer;
    renderer->AddActor(actor);
    renderer->SetBackground(0.2, 0.2, 0.2);
    vtkNew<vtkRenderWindow> renwin ;
    renwin->AddRenderer(renderer);
    renwin->SetSize(800, 800);
    vtkNew<vtkInteractorStyleTrackballCamera>style ;
    vtkNew<vtkRenderWindowInteractor> rendererwindowinteracrot ;
    rendererwindowinteracrot->SetInteractorStyle(style);
    rendererwindowinteracrot->SetRenderWindow(renwin);
    rendererwindowinteracrot->Start();
#else
    Q_UNUSED(surface);
#endif
}

void VtkUtil::ShowVtkDebugPolydata(vtkSmartPointer<vtkPolyData> surface,
                                   QList<quint32> self_intersected_list) {
#if ISDEBUGGING
    qSort(self_intersected_list.begin(), self_intersected_list.end());
    self_intersected_list = self_intersected_list.toSet().toList();
    unsigned char color1[3] = { 255, 0, 0 };
    unsigned char color2[3] = { 0, 0, 0 };
    vtkNew<vtkUnsignedCharArray> cellColor;
    cellColor->SetNumberOfComponents(3);

    for(quint32 id = 0; id < surface->GetNumberOfCells(); id++) {
        if(self_intersected_list.contains(id)) {
            cellColor->InsertNextTypedTuple(color1);
        } else {
            cellColor->InsertNextTypedTuple(color2);
        }
    }
    surface->GetCellData()->SetScalars(cellColor);
    vtkNew<vtkPolyDataMapper> polydatamapper ;
    polydatamapper->SetInputData(surface);
    vtkNew<vtkActor> actor ;
    actor->SetMapper(polydatamapper);
    // actor->GetProperty()->SetOpacity(0.1);
    vtkNew<vtkRenderer> renderer;
    renderer->AddActor(actor);
    renderer->SetBackground(0.2, 0.2, 0.2);
    vtkNew<vtkRenderWindow> renwin ;
    renwin->AddRenderer(renderer);
    renwin->SetSize(800, 800);
    vtkNew<vtkInteractorStyleTrackballCamera>style ;
    vtkNew<vtkRenderWindowInteractor> rendererwindowinteracrot ;
    rendererwindowinteracrot->SetInteractorStyle(style);
    rendererwindowinteracrot->SetRenderWindow(renwin);
    rendererwindowinteracrot->Start();
#else
    Q_UNUSED(surface);
    Q_UNUSED(self_intersected_list);
#endif
}

void VtkUtil::ShowVtkDebugPolydata(
    vtkSmartPointer<vtkImageData> surface) {
#if ISDEBUGGING
    vtkNew<vtkImageViewer2> imageViewer ;
    imageViewer->SetInputData(surface);
    vtkNew<vtkRenderWindowInteractor> renderWindowInteractor ;
    imageViewer->SetupInteractor(renderWindowInteractor);
    imageViewer->Render();
    imageViewer->GetRenderer()->ResetCamera();
    imageViewer->Render();
    renderWindowInteractor->Start();
#else
    Q_UNUSED(surface);
#endif
}

void VtkUtil::WriteVTP(
    vtkSmartPointer<vtkPolyData> surface, QString filename) {
#if ISDEBUGGING
    vtkNew<vtkXMLPolyDataWriter> writer;
    writer->SetFileName(filename.toLocal8Bit().data());
    writer->SetInputData(surface);
    writer->Write();
#else
    Q_UNUSED(surface);
    Q_UNUSED(filename);
#endif
}