转载请附上链接:
https://blog.csdn.net/l1783111653/article/details/108817264
问题描述:
在医学图像图像处理过程中,我们经常需要对分割后的图像进行彩色映射并将其与原始的灰度图像融合,以便于后续观察和诊断。网上有人用vtkLookupTable实现灰度图到彩色图的映射,然后用vtkImageBlend实现彩色图层和灰度图层的叠加显示,不过这种方法我还没有调试成功,这里介绍另一种彩色图层与灰度图层叠加显示的方法。解决方案:
这里仍然利用vtkLookupTable实现灰度图到彩色图的映射,后续借助vtkimageViewer2实现多个vtkImageActor的叠加显示。用vtkimageViewer2的原因在于它封装了完整的渲染管线,而且具有调节窗宽窗位、切换切片等功能。不过vtkimageViewer2封装过度也存在一些问题,当显示的图像为dicom序列时,不同切片间的切换需调用SetSlice()方法,而该方法每次都会调用Render方法;当存在多个图层(多个vtkimageViewer2)依次调用SetSlice()方法时就会出现闪烁的问题,如下图。 解决方法就是新建一个类(最后的代码中是vtkimageViewer2My),将vtkimageViewer2的代码粘过去,替换类名,并将SetSlice()方法中的this->Render();语句删掉。最后等所有图层切换好之后在调用Render()方法。//vtkImageViewer2的SetSlice方法源码
void vtkImageViewer2::SetSlice(int slice)
{
int *range = this->GetSliceRange();
if (range)
{
if (slice < range[0])
{
slice = range[0];
}
else if (slice > range[1])
{
slice = range[1];
}
}
if (this->Slice == slice)
{
return;
}
this->Slice = slice;
this->Modified();
this->UpdateDisplayExtent();
this->Render();
}
运行结果
开发环境
windows10、VS2017 、VTK8.2代码
下面用到的vtkImageViewer2My类的创建方法已经讲过了,仍然需要的话可以留下邮箱。
#pragma once
#include "pch.h"
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);
#include <vtkImageData.h>
#include <vtkProperty.h>
#include <vtkDataSetMapper.h>
#include <vtkRendererCollection.h>
#include <itkImageToVTKImageFilter.h>
#include <vtkPolyDataMapper.h>
#include <vtkDICOMImageReader.h>
#include <vtkPolyData.h>
#include <vtkPointData.h>
#include <vtkAxesActor.h>
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkMarchingCubes.h"
#include "vtkStripper.h"
#include "vtkActor.h"
#include "vtkSmoothPolyDataFilter.h"
#include "vtkPolyDataNormals.h"
#include "vtkImageShrink3D.h"
#include "vtkDecimatePro.h"
#include "vtkProperty.h"
#include <vtkInteractorStyleImage.h>
#include <vector>
#include <string>
#include <vtkSmartPointer.h>
#include <vtkImageActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkImageViewer2.h>
#include <vtkImageSliceMapper.h>
#include <vtkPNGReader.h>
#include <vtkSTLReader.h>
#include <vtkTexture.h>
#include <vtkTextureMapToCylinder.h>
#include <vtkImageFlip.h>
#include <vtkImageGradient.h>
#include <vtkImageGradient.h>
#include <vtkImageMagnitude.h>
#include <vtkImageShiftScale.h>
#include <vtkImageHybridMedian2D.h>
#include <vtkSphereSource.h>
#include <vtkTextProperty.h>
#include <vtkProperty2D.h>
#include <vtkSmartPointer.h>
#include <vtkPolyData.h>
#include <vtkSliderWidget.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkPolyData.h>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkCommand.h>
#include <vtkWidgetEvent.h>
#include <vtkCallbackCommand.h>
#include <vtkWidgetEventTranslator.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkSliderWidget.h>
#include <vtkSliderRepresentation2D.h>
#include <vtkProperty.h>
#include <vtkLookupTable.h>
#include <vtkImageProperty.h>
#include <vtkImageMapToColors.h>
#include "vtkImageViewer2My.h"
class vtkSliderCallback1 : public vtkCommand
{
public:
static vtkSliderCallback1 *New()
{
return new vtkSliderCallback1;
}
virtual void Execute(vtkObject *caller, unsigned long, void*)
{
vtkSliderWidget *sliderWidget =
reinterpret_cast<vtkSliderWidget*>(caller);
this->viewer->SetSlice(static_cast<vtkSliderRepresentation *>(sliderWidget->GetRepresentation())->GetValue());
if (this->viewer1 != nullptr)
this->viewer1->SetSlice(static_cast<vtkSliderRepresentation *>(sliderWidget->GetRepresentation())->GetValue());
this->viewer->Render();
}
vtkSliderCallback1() {
}
vtkSmartPointer<vtkImageViewer2My> viewer = nullptr;
vtkSmartPointer<vtkImageViewer2My> viewer1 = nullptr;
//vtkImageViewer2
};
vtkSmartPointer<vtkImageData> read3dImageByVtk(const char *path)
{
vtkSmartPointer<vtkDICOMImageReader> reader =
vtkSmartPointer<vtkDICOMImageReader>::New();
reader->SetDirectoryName(path);
reader->Update();
return reader->GetOutput();
}
void show3dImage(vtkSmartPointer<vtkImageData> image, vtkSmartPointer<vtkImageData> image1)
{
vtkSmartPointer<vtkImageViewer2My> viewer = vtkSmartPointer<vtkImageViewer2My>::New();
viewer->SetInputData(image1);
viewer->SetSlice(622);
viewer->SetSliceOrientationToXY();
viewer->GetRenderer()->SetBackground(0.5, 0.5, 0.5);
viewer->GetRenderWindow()->SetWindowName("ImageViewer2D");
vtkSmartPointer<vtkLookupTable> pColorTable = vtkSmartPointer<vtkLookupTable>::New();
pColorTable->SetNumberOfColors(2);
pColorTable->SetTableRange(0, 3071);
pColorTable->SetTableValue(0, 0.0, 0.0, 1.0, 0.0);
pColorTable->SetTableValue(1, 1, 0, 0, 1.0);
pColorTable->Build();
vtkSmartPointer<vtkImageViewer2My> viewerLayer = vtkSmartPointer<vtkImageViewer2My>::New();
viewerLayer->SetInputData(image);
viewerLayer->SetRenderWindow(viewer->GetRenderWindow());
viewerLayer->SetSliceOrientationToXY();
viewerLayer->SetSlice(622);
viewerLayer->GetImageActor()->SetInterpolate(false);
viewerLayer->GetImageActor()->GetProperty()->SetLookupTable(pColorTable);
viewerLayer->GetImageActor()->GetProperty()->SetDiffuse(0.0);
viewerLayer->GetImageActor()->SetPickable(false);
viewer->GetRenderer()->AddActor(viewerLayer->GetImageActor());
vtkSmartPointer<vtkInteractorStyleTrackballCamera> style =
vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
vtkSmartPointer<vtkRenderWindowInteractor> rwi =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
viewer->SetupInteractor(rwi);
//viewer->GetRenderer()->GetRenderWindow()->GetInteractor()->SetInteractorStyle(style);
vtkSmartPointer<vtkSliderRepresentation2D> sliderRep = vtkSmartPointer<vtkSliderRepresentation2D>::New();
sliderRep->SetMinimumValue(viewer->GetSliceMin());
sliderRep->SetMaximumValue(viewer->GetSliceMax());
sliderRep->SetValue(5.0);
sliderRep->GetSliderProperty()->SetColor(1, 0, 0);//red
sliderRep->GetTitleProperty()->SetColor(1, 0, 0);//red
sliderRep->GetLabelProperty()->SetColor(1, 0, 0);//red
sliderRep->GetSelectedProperty()->SetColor(0, 1, 0);//green
sliderRep->GetTubeProperty()->SetColor(1, 1, 0);//yellow
sliderRep->GetCapProperty()->SetColor(1, 1, 0);//yellow
sliderRep->GetPoint1Coordinate()->SetCoordinateSystemToDisplay();
sliderRep->GetPoint1Coordinate()->SetValue(40, 40);
sliderRep->GetPoint2Coordinate()->SetCoordinateSystemToDisplay();
sliderRep->GetPoint2Coordinate()->SetValue(500, 40);
vtkSmartPointer<vtkSliderWidget> sliderWidget = vtkSmartPointer<vtkSliderWidget>::New();
sliderWidget->SetInteractor(rwi);
sliderWidget->SetRepresentation(sliderRep);
sliderWidget->SetAnimationModeToAnimate();
sliderWidget->EnabledOn();
vtkSmartPointer<vtkSliderCallback1> callback = vtkSmartPointer<vtkSliderCallback1>::New();
callback->viewer = viewer;
callback->viewer1 = viewerLayer;
sliderWidget->AddObserver(vtkCommand::InteractionEvent, callback);
vtkSmartPointer<vtkAxesActor> axes = vtkSmartPointer<vtkAxesActor>::New();
double axesSize[3] = {
100,100,100 };
axes->SetTotalLength(axesSize);
axes->SetConeRadius(0.1);
axes->SetShaftTypeToLine();
axes->SetAxisLabels(false);
//viewer->GetRenderer()->AddActor(axes);
rwi->Start();
viewer->Render();
viewerLayer->Render();
}
int main()
{
const char *Input_Name1 = ("C:\\Users\\Desktop\\\segment\\SE4");//对应灰度图
const char *Input_Name2 = ("C:\\Users\\Desktop\\\segment\\out2");//对应彩色图
vtkSmartPointer<vtkImageData> image1 = read3dImageByVtk(Input_Name1);
vtkSmartPointer<vtkImageData> image2 = read3dImageByVtk(Input_Name2);
show3dImage(image2, image1);
return 0;
}