可以通过鼠标滚轮上下翻滚图像,鼠标移动实时获得坐标位置与像素值。
#include <vtkActor.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkObjectFactory.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkActor2D.h>
#include <vtkDICOMImageReader.h>
#include <vtkInteractorStyleImage.h> //为自定义交互式类准备
#include <vtkTextMapper.h>
#include <vtkTextProperty.h>
#include <vtkImageData.h>
#include <vtkImageActor.h>
#include <vtkAutoInit.h>
#include <vtkCamera.h>
#include <vtkImageProperty.h>
#include <vtkImageReslice.h>
#include <vtkImageMapper3D.h>
#include <vtkMatrix4x4.h>
#include <vtkLookupTable.h>
#include <vtkImageMapToColors.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);
VTK_MODULE_INIT(vtkRenderingContextOpenGL2);
#include <sstream>
namespace {
// helper class to format slice status message
class StatusMessage
{
public:
static std::string Format(int slice, int maxSlice,short pixels,int xx,int yy)
{
std::stringstream tmp;
tmp << "X " << xx << " Y " << yy << " Pixel " << pixels << "\n" << "Slice Number " << slice + 1 << "/" << maxSlice + 1;
return tmp.str();
}
};
// Define own interaction style
class myVtkInteractorStyleImage2 : public vtkInteractorStyleImage //自定义交互式类
{
public:
static myVtkInteractorStyleImage2* New();
vtkTypeMacro(myVtkInteractorStyleImage2, vtkInteractorStyleImage);
protected:
vtkImageReslice* _ImageReslice;
vtkImageMapToColors* _MapToColors;
vtkTextMapper* _StatusMapper;
vtkRenderWindowInteractor* _Interactor;
vtkRenderer* _Renderer;
vtkImageData* _imageData;
int _Slice;
int _MinSlice;
int _MaxSlice;
short PixelAndPosition[3] = { 0,-100,-100 };
public:
void SetImageReslice(vtkImageReslice* ImageReslice,int MinSlice,int MaxSlice, vtkImageMapToColors* MapToColors, vtkRenderWindowInteractor* Interactor, vtkRenderer* Renderer)
{
_ImageReslice = ImageReslice;
_MapToColors = MapToColors;
_Interactor = Interactor;
_Renderer = Renderer;
_MinSlice = MinSlice;
_MaxSlice = MaxSlice;
_Slice = _MinSlice;
cout << _Slice << endl;
_imageData = ImageReslice->GetOutput();
}
void SetStatusMapper(vtkTextMapper* statusMapper)
{
_StatusMapper = statusMapper;
}
protected:
void MoveSliceForward()
{
if (_Slice < _MaxSlice)
{
_Slice += 1;
_ImageReslice->Update();
double spacing = _ImageReslice->GetOutput()->GetSpacing()[2];
vtkMatrix4x4* matrix = _ImageReslice->GetResliceAxes();
double centz = matrix->GetElement(2, 3);
centz += spacing;
matrix->SetElement(2, 3, centz);
_MapToColors->Update();
_Interactor->Render();
_imageData = _ImageReslice->GetOutput();
MoveMouse();
std::string msg = StatusMessage::Format(_Slice, _MaxSlice, PixelAndPosition[0], PixelAndPosition[1], PixelAndPosition[2]);
_StatusMapper->SetInput(msg.c_str());
_MapToColors->Update();
_Interactor->Render();
}
}
void MoveSliceBackward()
{
if (_Slice > _MinSlice)
{
_Slice -= 1;
_ImageReslice->Update();
double spacing = _ImageReslice->GetOutput()->GetSpacing()[2];
vtkMatrix4x4* matrix = _ImageReslice->GetResliceAxes();
double centz = matrix->GetElement(2, 3);
centz -= spacing;
matrix->SetElement(2, 3, centz);
_MapToColors->Update();
_Interactor->Render();
_imageData = _ImageReslice->GetOutput();
MoveMouse();
std::string msg = StatusMessage::Format(_Slice, _MaxSlice, PixelAndPosition[0], PixelAndPosition[1], PixelAndPosition[2]);
_StatusMapper->SetInput(msg.c_str());
_MapToColors->Update();
_Interactor->Render();
}
}
void MoveMouse()
{
int* pos = this->GetInteractor()->GetEventPosition();
int* DataSize = _ImageReslice->GetOutput()->GetDimensions();
int* rendsize = _Renderer->GetSize();
int MinSize = 9999;
for (int i = 0; i < 2; i++)
{
if (rendsize[i] < MinSize)
{
MinSize = rendsize[i];
}
}
int* windowsize = _Interactor->GetRenderWindow()->GetSize();
int posmin_x = (windowsize[0] - MinSize) / 2;
int posmax_x = posmin_x + MinSize;
int posmin_y = (windowsize[1] - MinSize) / 2;
int posmax_y = posmin_y + MinSize;
float scales = float(DataSize[0]) / float(MinSize);
if (pos[0] >= posmin_x && pos[0] < posmax_x && pos[1] >= posmin_y && pos[1] < posmax_y)
{
int index_x = pos[0] - posmin_x;
int index_y = pos[1] - posmin_y;
int posxx = int(index_x * scales);
int posyy = int(index_y * scales);
if (posxx > DataSize[0] - 1)
{
posxx = DataSize[0] - 1;
}
if (posyy > DataSize[1] - 1)
{
posyy = DataSize[1] - 1;
}
short pixelvalue = (short)_imageData->GetScalarComponentAsDouble(posxx, posyy, 0, 0);
PixelAndPosition[0] = pixelvalue;
PixelAndPosition[1] = posxx;
PixelAndPosition[2] = posyy;
}
else
{
PixelAndPosition[0] = 0;
PixelAndPosition[1] = -100;
PixelAndPosition[2] = -100;
}
}
virtual void OnKeyDown()
{
std::string key = this->GetInteractor()->GetKeySym();
if (key.compare("Up") == 0)
{
MoveSliceForward();
}
else if (key.compare("Down") == 0)
{
MoveSliceBackward();
}
vtkInteractorStyleImage::OnKeyDown();
}
virtual void OnMouseWheelForward()
{
MoveSliceForward();
}
virtual void OnMouseWheelBackward()
{
if (_Slice > _MinSlice)
{
MoveSliceBackward();
}
}
virtual void OnMouseMove()
{
MoveMouse();
_MapToColors->Update();
_Interactor->Render();
std::string msg = StatusMessage::Format(_Slice, _MaxSlice, PixelAndPosition[0],PixelAndPosition[1], PixelAndPosition[2]);
_StatusMapper->SetInput(msg.c_str());
_MapToColors->Update();
_Interactor->Render();
vtkInteractorStyleImage::OnMouseMove();
}
};
vtkStandardNewMacro(myVtkInteractorStyleImage2); // 宏定义
} // namespace
int main()
{
// 创建 DICOM 图像阅读器
vtkSmartPointer<vtkDICOMImageReader> reader =
vtkSmartPointer<vtkDICOMImageReader>::New();
reader->SetDirectoryName("/*****");
reader->Update();
int dimss[3];
reader->GetOutput()->GetDimensions(dimss);
cout << "x:" << dimss[0] << "y:" << dimss[1] << "z:" << dimss[2] << endl;
//文字渲染器
// 创建图像 Actor
//vtkTextProperty是VTK中的一个类,主要用于控制文本(文字)属性的显示,包括文字大小、颜色、字体、对齐方式等。
vtkNew<vtkTextProperty> sliceTextProp;
sliceTextProp->SetFontFamilyToCourier(); //设置为Courier字体
sliceTextProp->SetFontSize(20); //字号为20
sliceTextProp->SetVerticalJustificationToBottom(); //一种对齐方式,默认水平居中对齐。SetVerticalJustificationToTop顶部对齐SetVerticalJustificationToBottom垂直对齐到底部
sliceTextProp->SetJustificationToLeft(); //左侧对齐(SetJustificationToLeft)或右侧对齐(SetJustificationToRight)。
//vtkTextProperty类通常与vtkTextMapper一起使用。vtkTextMapper是一个用于将一段字符串渲染成二维纹理贴图的类。
//使用vtkTextProperty,用户可以控制文本的各种属性,包括字体、颜色、大小、对齐方式等。
vtkNew<vtkTextMapper> sliceTextMapper;
std::string msg = StatusMessage::Format(0,
dimss[2] - 1,0,-100,-100);
sliceTextMapper->SetInput(msg.c_str()); // 设置要显示的文本内容
sliceTextMapper->SetTextProperty(sliceTextProp);
vtkNew<vtkActor2D> sliceTextActor;
sliceTextActor->SetMapper(sliceTextMapper);
sliceTextActor->SetPosition(15, 20); //设置文本位置(坐标左下角为(0,0),(x,y))
// usage hint message
vtkNew<vtkTextProperty> usageTextProp;
usageTextProp->SetFontFamilyToCourier();
usageTextProp->SetFontSize(14);
usageTextProp->SetVerticalJustificationToTop();
usageTextProp->SetJustificationToLeft();
vtkNew<vtkTextMapper> usageTextMapper;
usageTextMapper->SetInput(
"- Slice with mouse wheel\n or Up/Down-Key\n- Zoom with pressed right\n "
" mouse button while dragging");
usageTextMapper->SetTextProperty(usageTextProp);
vtkNew<vtkActor2D> usageTextActor;
usageTextActor->SetMapper(usageTextMapper);
usageTextActor->GetPositionCoordinate()
->SetCoordinateSystemToNormalizedDisplay(); //将该行文字的位置坐标系设置为规范化屏幕显示坐标系,其坐标原点位于窗口左下角,坐标范围在[0,1]之间。
usageTextActor->GetPositionCoordinate()->SetValue(0.05, 0.95); //根据范围设置位置
// 创建渲染器
vtkNew<vtkNamedColors> colors;
vtkSmartPointer<vtkRenderer> renderertext = vtkSmartPointer<vtkRenderer>::New();
renderertext->AddActor(usageTextActor);
renderertext->AddActor(sliceTextActor);
renderertext->SetBackground(colors->GetColor3d("SlateGray").GetData());
int extent[6];
double spacing[3];
double origin[3];
double center[3];
reader->GetOutput()->GetExtent(extent);
reader->GetOutput()->GetSpacing(spacing);
reader->GetOutput()->GetOrigin(origin);
center[0] = origin[0] + spacing[0] * 0.5 * (extent[0] + extent[1]);
center[1] = origin[1] + spacing[1] * 0.5 * (extent[2] + extent[3]);
center[2] = origin[2] ;
static double axialElements[16] = {
-1, 0, 0, 0,
0, 1, 0, 0,
0, 0, -1, 0,
0, 0, 0, 1 };
auto resliceAxes = vtkSmartPointer<vtkMatrix4x4>::New();
resliceAxes->DeepCopy(axialElements);
resliceAxes->SetElement(0, 3, center[0]);
resliceAxes->SetElement(1, 3, center[1]);
resliceAxes->SetElement(2, 3, center[2]);
vtkSmartPointer<vtkImageReslice> ImageReslice = vtkSmartPointer<vtkImageReslice>::New();
ImageReslice->SetInputConnection(reader->GetOutputPort());
ImageReslice->SetOutputDimensionality(2);
ImageReslice->AutoCropOutputOn();
double x[3] = { 1, 0, 0 };
double y[3] = { 0, -1, 0 };
double z[3] = { 0, 0, 1 };
#if 1
ImageReslice->SetResliceAxes(resliceAxes);
#else
ImageReslice->SetResliceAxesDirectionCosines(x, y, z);
ImageReslice->SetResliceAxesOrigin(center);
#endif
ImageReslice->SetInterpolationModeToLinear();
ImageReslice->Update();
auto lookupTable = vtkSmartPointer<vtkLookupTable>::New();
lookupTable->SetRange(-1250, 1250); //颜色映射的数值范围
lookupTable->SetValueRange(0.0, 1.0);//设置颜色映射的数值范围对应的颜色值范围,
lookupTable->SetSaturationRange(0.0, 0.0);//设置颜色映射的饱和度范围,这里将饱和度范围设置为 0.0,即无饱和度。
lookupTable->SetRampToLinear(); //将颜色映射设置为线性渐变模式,这意味着颜色将在数值范围内均匀分布。
lookupTable->Build();
auto mapToColors = vtkSmartPointer<vtkImageMapToColors>::New();
mapToColors->SetLookupTable(lookupTable);
mapToColors->SetInputConnection(ImageReslice->GetOutputPort());
mapToColors->Update();
auto imageActor = vtkSmartPointer<vtkImageActor>::New();
imageActor->GetMapper()->SetInputConnection(mapToColors->GetOutputPort());
auto renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->SetSize(800, 800);
auto renderer = vtkSmartPointer<vtkRenderer>::New();
renderer->AddActor(imageActor);
renderer->SetBackground(colors->GetColor3d("SlateGray").GetData());
// 设置视口大小为512x512,并使图像填充满视口
double viewportSizeX = 512 / 800.0;
double viewportSizeY = 512 / 800.0;
renderer->SetViewport((1.0 - viewportSizeX) / 2.0, (1.0 - viewportSizeY) / 2.0, (1.0 + viewportSizeX) / 2.0, (1.0 + viewportSizeY) / 2.0);
//设置相机位置,回填充满视口
vtkCamera* camera = renderer->GetActiveCamera();
camera->ParallelProjectionOn(); //用于将相机设置为平行投影模式。
double* V = camera->GetViewUp(); //获取相机视角的上方向向量。默认(0, 1, 0),表示相机视角的上方向为正Y轴方向。
V[0] = V[0];
V[1] = -1;
V[2] = V[2];
camera->SetViewUp(V);
int* windowSize = renderWindow->GetSize();
double xc = center[0]; //计算图像中心位置x
double yc = center[1]; //计算图像中心位置y
double xd = (extent[1] - extent[0] + 1) * spacing[0]; //图像物理宽
double yd = (extent[3] - extent[2] + 1) * spacing[1]; //图像物理高
double d = camera->GetDistance(); //获得相机的距离
double aspectwindow = static_cast<double>(windowSize[0]) / windowSize[1]; //计算窗口宽/高
double aspectImage = xd / yd; //图像宽/高
float RRR = 0;
if (aspectImage < aspectwindow) //如果窗口的宽高比较大
{
RRR = xd / aspectImage;
camera->SetParallelScale(0.5 * RRR);
}
else
{
RRR = xd / aspectwindow;
camera->SetParallelScale(0.5 * RRR);
}
renderWindow->AddRenderer(renderertext);
renderWindow->AddRenderer(renderer);
auto interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
vtkSmartPointer<myVtkInteractorStyleImage2> imagestyle =vtkSmartPointer<myVtkInteractorStyleImage2>::New();
imagestyle->SetStatusMapper(sliceTextMapper);
imagestyle->SetImageReslice(ImageReslice, extent[4], extent[5],mapToColors, interactor, renderer);
interactor->SetInteractorStyle(imagestyle);
interactor->SetRenderWindow(renderWindow);
interactor->Initialize();
renderWindow->Render();
interactor->Start();
return 0;
}
总结:如有哪位看到错误或者有更好的实现方式,请及时提醒我,“柯西的笔”公众号。希望可以获得更多的指导与学习,万分感谢。
以上就是本篇文章的全部内容,最后感谢阅读!
版权声明:本文为weixin_41202834原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。