开发环境:
- Windows 11 家庭中文版
- Microsoft Visual Studio Community 2019
- VTK-9.3.0.rc0
- vtk-example
demo解决问题: VTK 读取、预处理、处理和可视化医学图像数据的过程
图像读取和预处理:
- 程序使用 VTK 的图像阅读器
vtkImageReader2Factory
类读取作为命令行参数指定的输入图像文件。
程序会对输入图像数据进行类型转换vtkImageCast
,将标量类型转换为 double 类型,以便进一步处理。 - 对图像数据应用高斯平滑滤波器
vtkImageGaussianSmooth
,以减少噪音并创建更平滑的表示。
图像处理:
- 定义隐式球形函数
vtkSphere
并对其进行采样vtkSampleFunction
(m2->SetImplicitFunction(m1);
),以在图像数据中创建感兴趣的球形区域。 - 然后对采样球进行缩放
vtkImageShiftScale
(m3->SetInputConnection(m2->GetOutputPort());
此处输入时上一步中的感兴趣输出),并使用乘法对原始图像数据进行数学运算vtkImageMathematics
,从而有效地应用遮罩。
可视化:
- 程序使用 VTK 的图像演员类
vtkImageActor
为原始图像和滤波图像设置演员。 - 程序还定义了视口,用于在渲染窗口中显示原始图像和滤波图像。
- 程序还创建了两个独立的呈现器,用于在呈现窗口中并排显示原始图像和滤波图像。
- 然后,程序初始化呈现窗口,设置交互样式,并显示图像供用户交互。
以上演示了在一个应用程序中使用 VTK 读取、预处理、处理和可视化医学图像数据的过程。
prj name: AttachAttributes
#include <vtkImageActor.h>
#include <vtkImageCast.h>
#include <vtkImageGaussianSmooth.h>
#include <vtkImageMapper3D.h>
#include <vtkImageMathematics.h>
#include <vtkImageProperty.h>
#include <vtkImageReader2.h>
#include <vtkImageReader2Factory.h>
#include <vtkImageShiftScale.h>
#include <vtkInteractorStyleImage.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSampleFunction.h>
#include <vtkSphere.h>/*
这张核磁共振成像图显示了传感器位置可能导致的衰减。
通过除以人工确定的衰减曲线,可以去除伪影。该直方图显示了伪影如何以标量值簇的形式隐藏信息。
*/
int main(int argc, char* argv[])
{// Verify input arguments.if (argc != 2){std::cout << "Usage: " << argv[0]<< " Filename e.g. AttenuationArtifact.pgm" << std::endl;return EXIT_FAILURE;}/*vtkImageReader2Factory: 该类用于在给定文件路径名的情况下创建 vtkImageReader2 对象。它会在所有可用的阅读器上调用 CanReadFile,直到其中一个返回 true。可用的阅读器列表来自三个地方。在该类的 InitializeReaders 函数中,内置的 VTK 类会被添加到列表中,用户可以调用 RegisterReader,或者用户可以创建一个具有 CreateObject 方法的 vtkObjectFactory,该方法会在给定字符串 "vtkImageReaderObject "时返回一个新的 vtkImageReader2 子类。这样,应用程序就可以通过插件 dll 或调用 RegisterReader 来扩展新的阅读器。当然,vtk 发行版中的所有阅读器都会自动可用。*/// Read the imagevtkNew<vtkImageReader2Factory> readerFactory;vtkSmartPointer<vtkImageReader2> reader;reader.TakeReference(readerFactory->CreateImageReader2(argv[1]));reader->SetFileName(argv[1]);//vtkImageCast 过滤器会转换输入类型以匹配图像处理管道中的输出类型。//如果输入已具有正确的类型,则该过滤器不会执行任何操作。要指定 "CastTo "类型,请使用 "SetOutputScalarType "方法。vtkNew<vtkImageCast> cast;cast->SetInputConnection(reader->GetOutputPort());cast->SetOutputScalarTypeToDouble();// Get rid of discrete scalars.vtkNew<vtkImageGaussianSmooth> smooth;smooth->SetInputConnection(cast->GetOutputPort());smooth->SetStandardDeviations(0.8, 0.8, 0);vtkNew<vtkSphere> m1;m1->SetCenter(310, 130, 0);m1->SetRadius(0);vtkNew<vtkSampleFunction> m2;m2->SetImplicitFunction(m1);m2->SetModelBounds(0, 264, 0, 264, 0, 1);m2->SetSampleDimensions(264, 264, 1);//使用vtkImageShiftScale可以对像素进行平移(添加一个常量值)和缩放(乘以一个标量)。//作为一种便利,这个类允许你设置输出标量类型,类似于vtkImageCast。这是因为平移缩放操作经常会转换数据类型。vtkNew<vtkImageShiftScale> m3;m3->SetInputConnection(m2->GetOutputPort());m3->SetScale(0.000095);//https://blog.csdn.net/fandq1223/article/details/53185464vtkNew<vtkImageMathematics> div;div->SetInputConnection(0, smooth->GetOutputPort());div->SetInputConnection(1, m3->GetOutputPort());div->SetOperationToMultiply();// Create actors.vtkNew<vtkNamedColors> colors;double colorWindow = 256.0;double colorLevel = 127.5;vtkNew<vtkImageActor> originalActor;originalActor->GetMapper()->SetInputConnection(cast->GetOutputPort());originalActor->GetProperty()->SetColorWindow(colorWindow);originalActor->GetProperty()->SetColorLevel(colorLevel);vtkNew<vtkImageActor> filteredActor;filteredActor->GetMapper()->SetInputConnection(div->GetOutputPort());// Define viewport ranges.// (xmin, ymin, xmax, ymax)double originalViewport[4] = {0.0, 0.0, 0.5, 1.0};double filteredViewport[4] = {0.5, 0.0, 1.0, 1.0};// Setup renderers.vtkNew<vtkRenderer> originalRenderer;originalRenderer->SetViewport(originalViewport);originalRenderer->AddActor(originalActor);originalRenderer->ResetCamera();originalRenderer->SetBackground(colors->GetColor3d("SlateGray").GetData());vtkNew<vtkRenderer> filteredRenderer;filteredRenderer->SetViewport(filteredViewport);filteredRenderer->AddActor(filteredActor);filteredRenderer->ResetCamera();filteredRenderer->SetBackground(colors->GetColor3d("LightSlateGray").GetData());vtkNew<vtkRenderWindow> renderWindow;renderWindow->SetSize(600, 300);renderWindow->AddRenderer(originalRenderer);renderWindow->AddRenderer(filteredRenderer);renderWindow->SetWindowName("Attenuation");vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;vtkNew<vtkInteractorStyleImage> style;renderWindowInteractor->SetInteractorStyle(style);renderWindowInteractor->SetRenderWindow(renderWindow);renderWindow->Render();renderWindowInteractor->Initialize();renderWindowInteractor->Start();return EXIT_SUCCESS;
}