VS2022联合Qt5开发学习7(QT5.12.3联合VTK在VS2022上开发医学图像项目2——十字叉标注)

这篇博文是接着VS2022联合Qt5开发学习5(QT5.12.3联合VTK在VS2022上开发医学图像项目)-CSDN博客这篇博文延伸开发医学图像的显示渲染相关项目。三视图这个有点繁琐,还得先放放(可能是下一篇博文?),这一篇主要介绍的是在之前显示的图像上增加中心十字叉。(虽然看上去挺简单的,但是其实还是综合了很多我前面博文介绍过的内容的。)

用到的内容有:

11.VTK图形处理_vtkPolyData-CSDN博客

3.VTK坐标系统以及VTK管线_vtk时间管线-CSDN博客

VS2022联合Qt5开发学习5(QT5.12.3联合VTK在VS2022上开发医学图像项目)-CSDN博客

大家可以先提前瞅一眼,或者直接读这一篇博文,到了要用到的地方,我会都标上的。

这个项目我是接着前面那个博客的STLshowtest_vtk7项目,用的VTK版本是VTK7,也就是说,显示图像我用的是QVTKWidget这个控件。如果是用的VTK9或者其他更高版本的VTK,解决方案参考VS2022联合Qt5开发学习5(QT5.12.3联合VTK在VS2022上开发医学图像项目)-CSDN博客,里面我有详细写怎么用哈,这里就不赘述了。

我们可以看到,在那种比较成熟的医学图像显示项目里,图像上都有这种十字叉,有的是为了显示图像中心,有的是为了方便在图像中取点,以便进行之后的一些应用。(下图来源:Medical Imaging Interaction Toolkit: The MITK Workbench

我这里就简单构造一个专门画十字叉的函数了,具体怎么应用看大家的需求了。

首先,画线条这里我用到了vtkLine,所以记得在项目开头加上

#include<vtkLine.h>

 

然后构造十字叉的函数,放在.cpp文件里。

vtkSmartPointer<vtkActor> STLshowtest_vtk7::DrawCross(vtkSmartPointer<vtkActor> _Actor, double _Pos[3])
{
	if (_Actor == nullptr)
	{
		_Actor = vtkSmartPointer<vtkActor>::New();
	}

	vtkSmartPointer<vtkPoints> _Points = vtkSmartPointer<vtkPoints>::New();
	_Points->InsertNextPoint(_Pos[0] - 3, _Pos[1], _Pos[2]);
	_Points->InsertNextPoint(_Pos[0] + 3, _Pos[1], _Pos[2]);
	_Points->InsertNextPoint(_Pos[0], _Pos[1] - 3, _Pos[2]);
	_Points->InsertNextPoint(_Pos[0], _Pos[1] + 3, _Pos[2]);

	vtkSmartPointer<vtkLine> _Line0 = vtkSmartPointer<vtkLine>::New();
	_Line0->GetPointIds()->SetId(0, 0);
	_Line0->GetPointIds()->SetId(1, 1);

	vtkSmartPointer<vtkLine> _Line1 = vtkSmartPointer<vtkLine>::New();
	_Line1->GetPointIds()->SetId(0, 2);
	_Line1->GetPointIds()->SetId(1, 3);

	vtkSmartPointer<vtkCellArray> _Lines = vtkSmartPointer<vtkCellArray>::New();
	_Lines->InsertNextCell(_Line0);
	_Lines->InsertNextCell(_Line1);

	vtkSmartPointer<vtkPolyData> _PolyData = vtkSmartPointer<vtkPolyData>::New();
	_PolyData->SetPoints(_Points);
	_PolyData->SetLines(_Lines);

	vtkSmartPointer<vtkPolyDataMapper> _Mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
	_Mapper->SetInputData(_PolyData);

	vtkSmartPointer<vtkProperty> lineProperty = vtkSmartPointer<vtkProperty>::New();
	lineProperty->SetLineWidth(1.0);  // 设置线宽为 1,可以根据需要调整

	_Actor->SetMapper(_Mapper);
	_Actor->SetProperty(lineProperty);
	_Actor->GetProperty()->SetColor(1.0, 0.0, 0.0);

	return _Actor;
}

 

在.h文件加入函数和变量的声明

private:
    vtkSmartPointer<vtkRenderer> m_vtkRenderer;
    vtkSmartPointer<vtkRenderWindow> m_vtkRenderWindow;

private:
    vtkSmartPointer<vtkActor> DrawCross(vtkSmartPointer<vtkActor> _Actor, double _Pos[3]);

 

最后把位置参数设一下,然后把十字叉作为Actor推到渲染器Render里,然后再丢到窗口里就大功告成了。

STLshowtest_vtk7::STLshowtest_vtk7(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);

    //test DrawCross
	static vtkSmartPointer<vtkActor> _CrossCenterActor = vtkSmartPointer<vtkActor>::New();
	double _Pos[3];
	_Pos[0] = 0;
	_Pos[1] = 0;
	_Pos[2] = 0;
	_CrossCenterActor = DrawCross(_CrossCenterActor, _Pos);
	_CrossCenterActor->SetPosition(0, 0, 1);

	m_vtkRenderer = vtkSmartPointer<vtkRenderer>::New();
	m_vtkRenderer->AddActor(_CrossCenterActor);
	m_vtkRenderer->SetBackground(.0, .0, .0);

	vtkSmartPointer<vtkRenderWindow> window = vtkSmartPointer<vtkRenderWindow>::New();
	ui.qvtkWidget->SetRenderWindow(window);
	ui.qvtkWidget->GetRenderWindow()->AddRenderer(m_vtkRenderer); 
}

。。。我写的这么详细,应该不需要再把完整代码贴上了吧。

运行结果

进行到这一步会出现一个问题。一旦我们点击选择图像,导入.stl文件后,这个十字叉就会消失了,这显然也不是我们想要的结果。这时候就要祭出我之前学VTK的一篇博文了3.VTK坐标系统以及VTK管线_vtk时间管线-CSDN博客 (嘎嘎嘎所以说多记笔记多写心得是有好处的,这不就用上了)。这个博文里的例子就是一个窗口里加了好多个Actor和Render,可以参考参考。

修改openFileSlot()函数,把_CrossCenterActor加进去,一起和.stl文件的图像的Actor推到渲染器里。

void STLshowtest_vtk7::openFileSlot()
{
    QString selectFilePath = QFileDialog::getOpenFileName(this, QString("choose STL file"), QString(""), QString("file(*.stl)"));
    if (selectFilePath.isEmpty())
    {
        ui.textBrowser->append("The address of the STL file you choose is null!");
        return;
    }

    // 原始图像
    vtkSmartPointer<vtkSTLReader> reader = vtkSmartPointer<vtkSTLReader>::New();
    reader->SetFileName(selectFilePath.toStdString().c_str());
    reader->Update();

    //将source转换成mapper
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    mapper->SetInputConnection(reader->GetOutputPort());

    //送入渲染引擎进行显示
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);

	static vtkSmartPointer<vtkActor> _CrossCenterActor = vtkSmartPointer<vtkActor>::New();
	double _Pos[3];
	_Pos[0] = 0;
	_Pos[1] = 0;
	_Pos[2] = 0;
	_CrossCenterActor = DrawCross(_CrossCenterActor, _Pos);
	_CrossCenterActor->SetPosition(0, 0, 1);

    //渲染
    vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
    renderer->AddActor(actor);
    renderer->SetBackground(.0, .0, .0);
	renderer->AddActor(_CrossCenterActor);
	renderer->SetBackground(.0, .0, .0);


    //设置渲染窗口
    vtkSmartPointer<vtkRenderWindow> window = vtkSmartPointer<vtkRenderWindow>::New();
    ui.qvtkWidget->SetRenderWindow(window);
    ui.qvtkWidget->GetRenderWindow()->AddRenderer(renderer); //等价于window->AddRenderer(renderer);

    //ok
    ui.textBrowser->append(QString("upload the file:") + selectFilePath + QString(" succeed !"));
}

运行结果

 

红叉叉不大明显,让我放大一点

 

所以可以看到现在又出来了新的问题:红叉不在图像中心、红叉太小。

先解决十字叉太小的问题。修改一下这里的坐标就可以了

	vtkSmartPointer<vtkPoints> _Points = vtkSmartPointer<vtkPoints>::New();
	_Points->InsertNextPoint(_Pos[0] - 10, _Pos[1], _Pos[2]);
	_Points->InsertNextPoint(_Pos[0] + 10, _Pos[1], _Pos[2]);
	_Points->InsertNextPoint(_Pos[0], _Pos[1] - 10, _Pos[2]);
	_Points->InsertNextPoint(_Pos[0], _Pos[1] + 10, _Pos[2]);

 

我这里只改了XY轴的坐标,这对于二维图是够用了。但我这里读取的是三维图,先再加一个轴。

	vtkSmartPointer<vtkPoints> _Points = vtkSmartPointer<vtkPoints>::New();
	_Points->InsertNextPoint(_Pos[0] - 10, _Pos[1], _Pos[2]);
	_Points->InsertNextPoint(_Pos[0] + 10, _Pos[1], _Pos[2]);
	_Points->InsertNextPoint(_Pos[0], _Pos[1] - 10, _Pos[2]);
	_Points->InsertNextPoint(_Pos[0], _Pos[1] + 10, _Pos[2]);
	_Points->InsertNextPoint(_Pos[0], _Pos[1], _Pos[2] - 10);
	_Points->InsertNextPoint(_Pos[0], _Pos[1], _Pos[2] + 10);

	vtkSmartPointer<vtkLine> _Line0 = vtkSmartPointer<vtkLine>::New();
	_Line0->GetPointIds()->SetId(0, 0);
	_Line0->GetPointIds()->SetId(1, 1);

	vtkSmartPointer<vtkLine> _Line1 = vtkSmartPointer<vtkLine>::New();
	_Line1->GetPointIds()->SetId(0, 2);
	_Line1->GetPointIds()->SetId(1, 3);

	vtkSmartPointer<vtkLine> _Line2 = vtkSmartPointer<vtkLine>::New();
	_Line2->GetPointIds()->SetId(0, 4);
	_Line2->GetPointIds()->SetId(1, 5);

	vtkSmartPointer<vtkCellArray> _Lines = vtkSmartPointer<vtkCellArray>::New();
	_Lines->InsertNextCell(_Line0);
	_Lines->InsertNextCell(_Line1);
	_Lines->InsertNextCell(_Line2);

	vtkSmartPointer<vtkPolyData> _PolyData = vtkSmartPointer<vtkPolyData>::New();
	_PolyData->SetPoints(_Points);
	_PolyData->SetLines(_Lines);

运行结果

如果有对这些画线还有坐标不清楚的,可以看一下我这个博客11.VTK图形处理_vtkPolyData-CSDN博客,这里我还举了其他的例子。

 

接下来是要确定图形的中心点,确保十字叉正中中心,不管怎么放大缩小旋转都在中心位置。这里可以参考一下这个博文(7.VTK图像基本操作-CSDN博客)。

	// 获取图像信息
	vtkSmartPointer<vtkPolyData> polyData = reader->GetOutput(); 
	vtkSmartPointer<vtkPoints> points = polyData->GetPoints();  

	// 计算中心点坐标
	double center[3] = { 0.0, 0.0, 0.0 };
	for (vtkIdType i = 0; i < points->GetNumberOfPoints(); ++i) {
		double point[3];
		points->GetPoint(i, point);
		for (int j = 0; j < 3; ++j) {
			center[j] += point[j];
		}
	}
	for (int j = 0; j < 3; ++j) {
		center[j] /= points->GetNumberOfPoints();
	}
	cout << "The Center of the Picture:" << center[0] << " " << center[1] << " " << center[2] << endl;

 

计算好中心点,将中心点坐标带入到十字叉函数

	_CrossCenterActor = DrawCross(_CrossCenterActor, center);

就完工啦!

运行结果

  • 25
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值