本文介绍使用分割后的切片数据进行3维图像重建。医学图像处理中,使用深度学习分割感兴趣区域是主流形式,当我们拿到连续分割后的mask区域,需要对mask区域进行可视化展示。完整代码放在最后啦(* ̄︶ ̄)
我使用c++结合vtk实现3维重建演示。
1、将分割后的结果放在一个文件夹中,因为要进行体积重现,一定要保证感兴趣区域正确顺序连续性。
2、读入切片图像数据,从文件夹中遍历图片,我的切片图像有37张,所以设置0-36。
std::vector<std::string> fileNames;
for (int i = 0; i <= 36; ++i) {
std::stringstream ss;
ss << R"(D:\tumor\1_0_)" << i << ".jpg"; // 替换为实际文件路径
fileNames.push_back(ss.str());
}
// 创建JPEG读取器
vtkSmartPointer<vtkJPEGReader> reader = vtkSmartPointer<vtkJPEGReader>::New();
reader->SetFileName(fileNames[0].c_str()); // 设置第一个切片文件
reader->Update();
3、创建体数据volumeData,为每一体数据分配内存,我设置维度为(512,512,37)。
vtkSmartPointer<vtkImageData> volumeData = vtkSmartPointer<vtkImageData>::New();
volumeData->SetDimensions(512, 512, 37); // 设置体数据维度
volumeData->AllocateScalars(VTK_UNSIGNED_CHAR, 1); // 分配内存
4、将每个切片图像的数据逐像素复制到三维体数据volumeData中,从而构建出一个完整的三维体。
for (int z = 0; z < fileNames.size(); ++z) {
reader->SetFileName(fileNames[z].c_str());
reader->Update();
vtkImageData* slice = reader->GetOutput();
for (int y = 0; y < 512; ++y) {
for (int x = 0; x < 512; ++x) {
unsigned char* pixel = static_cast<unsigned char*>(slice->GetScalarPointer(x, y, 0));
volumeData->SetScalarComponentFromDouble(x, y, z, 0, *pixel);
}
}
}
5、最后就是经典的体渲染套路,创建颜色传递函数、mapper、volume等等。
数据展示效果
6、完整代码放在最后,希望可以帮助你ヾ(◍°∇°◍)ノ゙
std::vector<std::string> fileNames;
for (int i = 0; i <= 36; ++i) {
std::stringstream ss;
ss << R"(D:\tumor\1_0_)" << i << ".jpg"; // 替换为实际文件路径
fileNames.push_back(ss.str());
}
// 创建JPEG读取器
vtkSmartPointer<vtkJPEGReader> reader = vtkSmartPointer<vtkJPEGReader>::New();
reader->SetFileName(fileNames[0].c_str()); // 设置第一个切片文件
reader->Update();
vtkSmartPointer<vtkImageData> volumeData = vtkSmartPointer<vtkImageData>::New();
volumeData->SetDimensions(512, 512, 37); // 设置体数据维度
volumeData->AllocateScalars(VTK_UNSIGNED_CHAR, 1); // 分配内存
for (int z = 0; z < fileNames.size(); ++z) {
reader->SetFileName(fileNames[z].c_str());
reader->Update();
vtkImageData* slice = reader->GetOutput();
for (int y = 0; y < 512; ++y) {
for (int x = 0; x < 512; ++x) {
unsigned char* pixel = static_cast<unsigned char*>(slice->GetScalarPointer(x, y, 0));
volumeData->SetScalarComponentFromDouble(x, y, z, 0, *pixel);
}
}
}
// 设置不透明度传递函数
vtkSmartPointer<vtkPiecewiseFunction> opacityTransferFunction = vtkSmartPointer<vtkPiecewiseFunction>::New();
opacityTransferFunction->AddPoint(0, 0.0);
opacityTransferFunction->AddPoint(255, 1.0);
// 设置颜色传递函数
vtkSmartPointer<vtkColorTransferFunction> colorTransferFunction = vtkSmartPointer<vtkColorTransferFunction>::New();
colorTransferFunction->AddRGBPoint(0, 0.0, 0.0, 0.0);
colorTransferFunction->AddRGBPoint(255, 1.0, 1.0, 1.0);
// 设置体渲染属性
vtkSmartPointer<vtkVolumeProperty> volumeProperty = vtkSmartPointer<vtkVolumeProperty>::New();
volumeProperty->SetColor(colorTransferFunction);
volumeProperty->SetScalarOpacity(opacityTransferFunction);
volumeProperty->ShadeOn();
volumeProperty->SetInterpolationTypeToLinear();
// 设置体数据映射器
vtkSmartPointer<vtkFixedPointVolumeRayCastMapper> volumeMapper = vtkSmartPointer<vtkFixedPointVolumeRayCastMapper>::New();
volumeMapper->SetInputData(volumeData);
// 创建体对象
vtkSmartPointer<vtkVolume> volume = vtkSmartPointer<vtkVolume>::New();
volume->SetMapper(volumeMapper);
volume->SetProperty(volumeProperty);
// 创建渲染器和渲染窗口
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
// 创建交互器
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
// 将体数据添加到渲染器
renderer->AddVolume(volume);
renderer->SetBackground(0.1, 0.8, 0.8);
// 启动渲染和交互
renderWindow->Render();
renderWindowInteractor->Start();