在Qt中使用OpenGL显示数据点

在Qt中使用OpenGL绘制三维点阵

前言:最近在做医学图像处理方面的东西,估计要进行三维重建,初步确定使用Qt+OpenGL作为框架进行开发。第一步,设想是需要显示三维点云,因此先写个能显示几个点的demo,要求能染色,可以调节视角及观察者的位置。

需要的工具及相关包和库:

  • VSCode 1.80.2
  • CMake 3.26.4
  • Qt 5.12.2
  • DCMTK 3.6.7(读取dicom文件需要用到,可选)

下载好后上述工具与包之后,需要配置CMake, Qt和DCMTK的环境变量,不然构建项目的时候会找不到路径。

显示三维数据点

Qt+OpenGL显示三维数据点

我们在初始化的时候,需要从一定的距离来观察,因此设置一下摄像机的move, 顶点数据放在_vertices数组中,八个点其实就是立方体的八个顶点,然后给他们两两染上好看的颜色,用于在摄像机移动过程中观察他们的位置变化。

ViewWidget::ViewWidget(QWidget* parent) : QOpenGLWidget(parent) {
	startTimer(1000 / 60);

    m_camera.move(-9, 0, 3);
	m_camera.look(0, 0, 0);
	m_camera.update();

	installEventFilter(&m_camera);
}


void ViewWidget::initializeGL() {
	initializeOpenGLFunctions();
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
	glClearColor(0, 0, 0, 1.0);

	// 设置立方体的顶点
	float _vertices[] = {
		// position    color
		 1,  1,  1,   1, 0, 0, // red
		 1,  1, -1,   1, 0, 0,
		-1,  1, -1,   0, 1, 0, // green
		-1,  1,  1,   0, 1, 0,
		 1, -1,  1,   1, 1, 0, // yellow
		 1, -1, -1,	  1, 1, 0, 
		-1, -1,  1,   0, 0, 1, // blue
		-1, -1, -1,   0, 0, 1, 
	};

	// 初始化并绑定vao
	m_vao.create();
	m_vao.bind();

	// 初始化并激活vbo
	m_vbo.create();
	m_vbo.bind();
	m_vbo.allocate(_vertices, 6 * 8 * sizeof(float));

	// 如果用m_program->create()会出现访问冲突
	m_program = new QOpenGLShaderProgram();
	m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/resources/shader/vertex.shader");
	m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/resources/shader/fragment.shader");
	m_program->link();

	// 设置shader里面的传入变量值参数
	m_program->bind();
	m_program->setAttributeBuffer("vPos", GL_FLOAT, 0 * sizeof(float), 3, 6 * sizeof(float));
	m_program->enableAttributeArray("vPos");

	m_program->setAttributeBuffer("vColor", GL_FLOAT, 3 * sizeof(float), 3, 6 * sizeof(float));
	m_program->enableAttributeArray("vColor");


	m_vao.release();
	m_vbo.release();
	m_program->release();

	// 设置物体位置为原来的位置,这里暂时没有用到
	m_model.setToIdentity();
}

显示DICOM数据点云

  有了这个基础,我们就可以显示文件中的点云了,首先通过DCMTK库把dicom中相关信息读出来,而后再把数据点的坐标乘以对应的spacing(这里x, y, z的spacing有可能完全不一样,需要从一张图片中读取)。

Qt+OpenGL显示dicom图像点云

  显示图片数据时需要仔细地调整相机位置,并且转动视角方向,不然可能即使对象已经渲染出来了,但是仍然无法呈现在屏幕上让我们观察。因此在这里我觉得有必要先学一下OpenGL中的摄像机,再做这个点云会更好。

void ViewWidget::initializeGL() {
	resize(QSize(800, 600));
	initializeOpenGLFunctions();
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
	glClearColor(0, 0, 0, 1.0);

	ImageInfo imageInfo;
	ReadFile::Read_Dicom_Info(imageInfo);
	int width = imageInfo.Width, height = imageInfo.Height, slices = imageInfo.Slice_num;
	float widthSpacing = imageInfo.Spacing[0], heightSpacing = imageInfo.Spacing[1], slicesSpacing = imageInfo.Spacing[2];
	shared_ptr<uint16_t> imageData(new uint16_t[width * height * slices]);
	ReadFile::Read_Dicom_File(imageData, slices, width * height);

	vector<float> _vertices;
	// -12851, 1023,这里最大最小值暂时没有用到
	short minValue = 32767, maxValue = -32768;
	for(int i = 0; i < width; i++) {
		for(int j = 0; j < height; j++) {
			for(int k = 0; k < slices; k++) {
				short value = (short)imageData.get()[k * width * height + j * width + i];
				if(value >= 400) {
					_vertices.push_back(i * widthSpacing);
					_vertices.push_back(j * heightSpacing);
					_vertices.push_back(k * slicesSpacing);
				}

				if(value < minValue) {
					minValue = value;
				}

				if(value > maxValue) {
					maxValue = value;
				}
			}
		}
	}
	vertexCount = _vertices.size();

	m_vao.create();
	m_vao.bind();

	m_vbo.create();
	m_vbo.bind();
	m_vbo.allocate(_vertices.data(), vertexCount * sizeof(float));

	m_program = new QOpenGLShaderProgram(); // 如果用m_program->create()会出现访问冲突
	m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/resources/shader/vertex.shader");
	m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/resources/shader/fragment.shader");
	m_program->link();

	m_program->bind();
	m_program->setAttributeBuffer("vPos", GL_FLOAT, 0 * sizeof(float), 3, 3 * sizeof(float));
	m_program->enableAttributeArray("vPos");

	m_vao.release();
	m_vbo.release();
	m_program->release();

	// 设置物体位置为原来的位置
	m_model.setToIdentity();
}

如果以上内容对你有帮助,不妨点个赞再走🌹.

最后附上代码地址:https://gitee.com/inavacuum/show-dicom-points

参考博客:https://blog.csdn.net/github_18974657/article/details/122453424?spm=1001.2014.3001.5502

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值