提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
最近在学习使用vtkContourWidget这个类,就简单记录下学习过程。
一、简单介绍
vtkCardinalSpline 、vtkKochenekSpline 、 vtkParametricSpline 、vtkSCurveSpline这几个都挺类似有时间挨个看一遍
二、具体实现
1.头文件widget.h:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <vtkSmartPointer.h>
#include <vtkDICOMImageReader.h>
#include <vtkImageViewer2.h>
#include <vtkImageAppend.h>
#include <vtkAutoInit.h>
#include <vtkContourWidget.h>
#include <vtkOrientedGlyphContourRepresentation.h>
#include <vtkImageActorPointPlacer.h>
#include <QVTKOpenGLWidget.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2); // VTK was built with vtkRenderingOpenGL2
VTK_MODULE_INIT(vtkRenderingFreeType);
VTK_MODULE_INIT(vtkInteractionStyle);
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
void initWidget(vtkImageViewer2* imageViewer, vtkImageData* imageData, QVTKOpenGLWidget *widget);
private slots:
void on_pbDrawContour_clicked();
void on_pbROI_clicked();
private:
Ui::Widget *ui;
vtkSmartPointer<vtkImageViewer2> m_sourceImageView;
vtkSmartPointer<vtkImageViewer2> m_roiImageView;
vtkImageData* m_imageData;
vtkSmartPointer<vtkOrientedGlyphContourRepresentation> m_rep;
vtkSmartPointer<vtkContourWidget> m_contourWidget;
};
#endif // WIDGET_H
2.实现widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <vtkRenderWindow.h>
#include <QDebug>
#include <vtkImageEllipsoidSource.h>
#include <vtkImageData.h>
#include <vtkImageMask.h>
#include <vtkProperty.h>
#include <vtkPolyDataToImageStencil.h>
#include <vtkImageStencilToImage.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkJPEGReader.h>
#include <vtkDataArray.h>
#include <vtkPointData.h>
#include <vtkXMLImageDataReader.h>
#include <vtkImageShiftScale.h>
#include <vtkMetaImageWriter.h>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
vtkSmartPointer<vtkImageData> image = vtkSmartPointer<vtkImageData>::New();
vtkSmartPointer<vtkXMLImageDataReader> reader = vtkSmartPointer<vtkXMLImageDataReader>::New();
reader->SetFileName("test.vti");
reader->Update();
m_imageData = reader->GetOutput();
m_sourceImageView = vtkSmartPointer< vtkImageViewer2 >::New();
m_roiImageView = vtkSmartPointer< vtkImageViewer2 >::New();
initWidget(m_sourceImageView, m_imageData, ui->sourceWidget);
initWidget(m_roiImageView, m_imageData, ui->roiWidget);
}
Widget::~Widget()
{
delete ui;
}
void Widget::initWidget(vtkImageViewer2 *imageViewer, vtkImageData *imageData, QVTKOpenGLWidget *widget)
{
imageViewer->SetInputData(imageData); // 加载数据
// 设置交互对象
imageViewer->SetupInteractor(widget->GetInteractor());
// 设置渲染窗口actor
imageViewer->SetRenderWindow(widget->GetRenderWindow());
// 设置交互样式
vtkSmartPointer<vtkInteractorStyleImage> m_style = vtkSmartPointer<vtkInteractorStyleImage>::New();
widget->GetRenderWindow()->GetInteractor()->SetInteractorStyle(m_style);
imageViewer->SetSliceOrientationToXY();
imageViewer->Render();
}
void Widget::on_pbDrawContour_clicked()
{
m_contourWidget = vtkSmartPointer<vtkContourWidget>::New();
m_rep = vtkSmartPointer<vtkOrientedGlyphContourRepresentation>::New();
m_rep->GetLinesProperty()->SetColor(1, 0, 0); // Set color to red
m_rep->GetLinesProperty()->SetLineWidth(2);
m_contourWidget->SetRepresentation(m_rep);
vtkSmartPointer<vtkImageActorPointPlacer> p_w_picpathActorPointPlacer = vtkSmartPointer<vtkImageActorPointPlacer>::New();
p_w_picpathActorPointPlacer->SetImageActor(m_sourceImageView->GetImageActor());
m_rep->SetPointPlacer(p_w_picpathActorPointPlacer);
m_contourWidget->SetInteractor(ui->sourceWidget->GetRenderWindow()->GetInteractor());
m_contourWidget->SetEnabled(true);
m_contourWidget->ProcessEventsOn();
}
void Widget::on_pbROI_clicked()
{
double *spacing = m_imageData->GetSpacing();
double *origin = m_imageData->GetOrigin();
int *dims = m_imageData->GetDimensions();
// 将 polydata 转换为 二值图像
// 1、从 ContourWidget 提取 polydata 数据并处理
vtkPolyData * polydata = m_rep->GetContourRepresentationAsPolyData();
vtkSmartPointer<vtkPolyDataToImageStencil> polyDataToImageStencil = vtkSmartPointer<vtkPolyDataToImageStencil>::New();
polyDataToImageStencil->SetInputData(polydata);
polyDataToImageStencil->SetOutputOrigin(origin);
polyDataToImageStencil->SetOutputSpacing(spacing);
polyDataToImageStencil->SetOutputWholeExtent(0, dims[0] - 1, 0, dims[1] - 1, 0, 0);//设置范围
polyDataToImageStencil->Update();
// 2、将 polydata 转换为 二值图像
vtkSmartPointer<vtkImageStencilToImage> imageStencilToImage = vtkSmartPointer<vtkImageStencilToImage>::New();
imageStencilToImage->SetInputConnection(polyDataToImageStencil->GetOutputPort());
imageStencilToImage->SetInsideValue(255); // 封闭图像内部为白色
imageStencilToImage->SetOutsideValue(0); // 封闭图像外部为黑色
imageStencilToImage->Update();
//3、将输入图像灰度调整到0-255范围
double ImageOriRange[2];
m_imageData->GetScalarRange(ImageOriRange);//图像灰度范围最小值、最大值
vtkSmartPointer<vtkImageShiftScale> shiftScaleFilter = vtkSmartPointer<vtkImageShiftScale>::New();
shiftScaleFilter->SetInputData(m_imageData);
shiftScaleFilter->SetShift(-1.0*ImageOriRange[0]);//用于设置偏移量Shift
shiftScaleFilter->SetScale(255.0 / (ImageOriRange[1] - ImageOriRange[0]));//将灰度级变为0-255
shiftScaleFilter->SetOutputScalarTypeToFloat();//>SetOutputScalarTypeToUnsignedChar();//指定其数据类型为UnsignedChar
shiftScaleFilter->Update();
m_imageData->DeepCopy(shiftScaleFilter->GetOutput());
// 4、提取 ROI 区域(这里提取的ROI区域就是我们所看见的那一层图像)
vtkNew<vtkImageMask> maskFilter;
maskFilter->SetInputData(0, m_imageData);
maskFilter->SetInputData(1, imageStencilToImage->GetOutput());
maskFilter->SetMaskedOutputValue(0,0,0);
maskFilter->Update();
vtkSmartPointer<vtkImageData> roiImage = vtkSmartPointer<vtkImageData>::New();
roiImage = maskFilter->GetOutput();
//保存提取的区域(保存后可验证提取的ROI区域就是我们所看见的那一层图像)
vtkSmartPointer<vtkMetaImageWriter> write = vtkSmartPointer<vtkMetaImageWriter>::New();
write->SetInputData(roiImage);
write->SetFileName("roi.mha");
write->Write();
//5、显示
m_roiImageView->SetInputData(roiImage);
m_roiImageView->Render();
//6、计算ROI封闭区域的像素点个数,灰度均值,灰度最小值,灰度最大值
int *dim = roiImage->GetDimensions();
int num = 0;
int pixelmax = 0;
int pixelmin = 100;
int sum = 0;
for (int k = 0; k < dim[2]; ++k)
{
for (int i = 0; i < dim[1]; ++i)
{
for (int j = 0; j < dim[0]; ++j)
{
float* ptr1 = static_cast<float*>(roiImage->GetScalarPointer(i, j, k));
if (*ptr1 > 0)
{
cout << "I am not zero:" << endl;
num++;
if (*ptr1 > pixelmax)
{
pixelmax = *ptr1;
}
if (*ptr1 < pixelmin);
{
pixelmin = *ptr1;
}
sum += *ptr1;
}
}
}
}
cout << "The pixels maximum is:" << pixelmax << endl;
cout << "The pixels minimum is:" << pixelmin << endl;
cout << "The total pixels num or Area is:" << num << endl;
cout << "The mean pixels is:" << sum / num << endl;
}