QT-OpenGL将灰度图像转成3D图形

2 篇文章 0 订阅
2 篇文章 0 订阅

要转换的灰度图:

转换后的效果:

颜色翻转后的效果:

代码实现:

使用到的头文件:

#include <QtWidgets/QWidget>
#include "ui_qtopengl.h"
#include <QOpenGLWidget>
#include <atltypes.h>
#include <QDir>
#include <QString>
#include <qtextstream.h>
#include "lib/GLU.H"
#include <QMouseEvent>
#include <QWheelEvent>

参数定义:

#define MAP_SIZE_W 1817//图片的宽的像素
#define MAP_SIZE_H 2730//图片的长的像素
#define STEP_SIZE 8 // 相邻顶点的距离
bool bRender = TRUE; // true为多边形渲染,false为线渲染
BYTE g_HeightMap[MAP_SIZE_W*MAP_SIZE_H]; // 保存高度数据

头文件:

class QtOpenGLMap : public QOpenGLWidget
{
	Q_OBJECT

public:
	QtOpenGLMap(QWidget *parent = Q_NULLPTR);
	~QtOpenGLMap();
private:
	Ui::QtOpenglClass ui;
protected:
	void initializeGL();
	void resizeGL(int w, int h);
	void paintGL();
	void mousePressEvent(QMouseEvent*event);
	void mouseMoveEvent(QMouseEvent * e);
	void wheelEvent(QWheelEvent *event);
private:
	GLfloat m_yAngle = 0.0f;
	GLfloat m_xAngle = 0.0f;
	GLfloat m_zAngle = 0.0f;
	GLfloat m_xPos = 0.0f;
	GLfloat m_yPos = 0.0f;
	GLfloat m_zPos = 0.0f;
	CPoint m_MouseDownPoint;
	float m_Scale = 0.1f;
	float m_ViewScale = 0.1f;	
private:
	void LoadRawFile(BYTE *pHeightMap);
	int Height(BYTE *pHeightMap, int X, int Y);
	void SetVertexColor(BYTE *pHeightMap, int x, int y);
	void RenderHeightMap(BYTE pHeightMap[]);
};

实现:

//QT自带的函数,进行OpenGL的初始化
void QtOpenGLMap::initializeGL()
{
	glClearColor(0.6f, 0.6f, 0.6f, 1.0f);//灰色背景
	glShadeModel(GL_SMOOTH);
	glClearDepth(1.0);
	glEnable(GL_DEPTH_TEST);
	// 载入1817*2730的高度图到g_HeightMap数组中
	LoadRawFile(g_HeightMap);
}
//QT自带的OpenGL函数
void QtOpenGLMap::resizeGL(int w, int h)
{
	glViewport(0, 0, (GLint)w, (GLint)h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	//gluPerspective(45.0, (GLfloat)w / (GLfloat)h, 0.1, 100.0);
	if (w < h)
		glOrtho(-10.0, 100.0, -10.0*(GLfloat)h / (GLfloat)w, 10.0*(GLfloat)h / (GLfloat)w, -100.0, 100.0);
	else
		glOrtho(-10.0*(GLfloat)w / (GLfloat)h, 10.0*(GLfloat)w / (GLfloat)h, -10.0, 10.0, -100.0, 100.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();//重置矩阵
}
//QT自带的函数,绘制图形
void QtOpenGLMap::paintGL()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();

	glPushMatrix();
        //用于鼠标在屏幕上移动时3D图的旋转、缩放
		glTranslatef(m_xPos, m_yPos, m_zPos);//平移
		glRotatef(m_xAngle, 1.0f, 0.0f, 0.0f);//绕x轴旋转
		glRotatef(m_yAngle, 0.0f, 1.0f, 0.0f);//绕y轴选择	
		glScalef(m_Scale, m_Scale, m_Scale);//缩放
		RenderHeightMap(g_HeightMap);//绘制3D图
	glPopMatrix();
}
//读取图片,并将灰度数据放入数组
void QtOpenGLMap::LoadRawFile(BYTE *pHeightMap)
{	
	QString fileName = "di1.png";
	QDir dir = QDir::current();
	QString path = dir.filePath(fileName);
	QImage *img = new QImage(path);
	int width = img->width();//图像宽
	int height = img->height();//图像高
	unsigned char *data = img->bits();//获取图像像素字节数据的首地址
	unsigned char r, g, b;
	int size = 0;
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			r = *(data + 2);
			g = *(data + 1);
			b = *data;
			pHeightMap[size] = (r + g + b) / 3;//得到灰度值
			size++;
			/*graydata[i*bytePerLine + j * 3] = (r * 30 + g * 59 + b * 11) / 100;
			graydata[i*bytePerLine + j * 3 + 1] = (r * 30 + g * 59 + b * 11) / 100;
			graydata[i*bytePerLine + j * 3 + 2] = (r * 30 + g * 59 + b * 11) / 100;*/

			data += 4;
		}
	}
}
void QtOpenGLMap::RenderHeightMap(BYTE pHeightMap[]) // 根据高度图渲染输出高度
{
	int X = 0, Y = 0; // 设置循环变量
	int x, y, z;
	if (!pHeightMap) return; // 确认高度图存在
	if (bRender) // 选择渲染模式
		glBegin(GL_QUADS); // 渲染为四边形
	else
		glBegin(GL_LINES); // 渲染为直线
	//下面的函数求得每一点的坐标和颜色,调用OpenGL渲染
		for (X = 0; X < MAP_SIZE_W; X += STEP_SIZE)
			for (Y = 0; Y < MAP_SIZE_H; Y += STEP_SIZE)
			{
				// 绘制(x,y)处的顶点
				// 获得(x,y,z)坐标
				x = X;
				y = Height(pHeightMap, X, Y) ; 
				z = Y;
				// 设置顶点颜色
				SetVertexColor(pHeightMap, x, z);
				glVertex3i((x - MAP_SIZE_W / 2)*0.1, y *0.1, (z- MAP_SIZE_H / 2)*0.1); // 调用OpenGL绘制顶点的命令,并将位置进行偏移
				// 绘制(x,y+1)处的顶点
				x = X;
				y = Height(pHeightMap, X, Y + STEP_SIZE);
				z = Y + STEP_SIZE;
				SetVertexColor(pHeightMap, x, z);
                //将位置进行偏移
				glVertex3i((x - MAP_SIZE_W / 2)*0.1, y*0.1, (z- MAP_SIZE_H / 2)*0.1);
				// 绘制(x+1,y+1)处的顶点
				x = X + STEP_SIZE;
				y = Height(pHeightMap, X + STEP_SIZE, Y + STEP_SIZE);
				z = Y + STEP_SIZE;
				SetVertexColor(pHeightMap, x, z);
				glVertex3i((x - MAP_SIZE_W / 2)*0.1, y *0.1, (z- MAP_SIZE_H / 2)*0.1);
				// 绘制(x+1,y)处的顶点
				x = X + STEP_SIZE;
				y = Height(pHeightMap, X + STEP_SIZE, Y);
				z = Y;
				SetVertexColor(pHeightMap, x, z);
				glVertex3i((x - MAP_SIZE_W / 2)*0.1, y *0.1, (z- MAP_SIZE_H / 2)*0.1);
			}
		glEnd();
		glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // 重置颜色
}
// 按高度设置顶点的颜色,越高的地方越亮
void QtOpenGLMap::SetVertexColor(BYTE *pHeightMap, int x, int y) 
{
	if (!pHeightMap) return;
    //float fColor =  ((256-Height(pHeightMap, x, y)) / 256.0f);//将颜色反转
	float fColor = ( Height(pHeightMap, x, y) / 256.0f);
	
	// 设置顶点的颜色(灰度),也可只设置其中一种颜色
	glColor3f(fColor, fColor, fColor);
}
// 下面的函数返回(x,y)点的高度
int QtOpenGLMap::Height(BYTE *pHeightMap, int X, int Y) 
{
	int x = X % MAP_SIZE_W; // 限制X的值在0-MAP_SIZE_W之间
	int y = Y % MAP_SIZE_H; // 限制Y的值在0-MAP_SIZE_H之间
	if (!pHeightMap) return 0; // 检测高度图是否存在,不存在则返回0
	return pHeightMap[x + (y * MAP_SIZE_W)]; // 返回(x,y)的高度
}
//鼠标点击事件,当鼠标点击时记录下点击位置
void QtOpenGLMap::mousePressEvent(QMouseEvent* event) {
	if (event->buttons() == Qt::LeftButton) {//如果鼠标按下的是左键
		CPoint point{ event->x() ,event->y() };
		m_MouseDownPoint = point;
	}
}
//鼠标移动事件,移动时改变旋转角度
void QtOpenGLMap::mouseMoveEvent(QMouseEvent * e)
{
	if (e->buttons() == Qt::LeftButton) {//如果鼠标按下的是左键
		m_xAngle += (e->y() - m_MouseDownPoint.y) / 3.6;
		m_yAngle += (e->x() - m_MouseDownPoint.x) / 3.6;
		CPoint point{ e->x() ,e->y() };
		m_MouseDownPoint = point;
	}
	update();
}
//鼠标滚轮事件,对3D图进行放大缩小
void QtOpenGLMap::wheelEvent(QWheelEvent *event)
{
	if (m_Scale >= 0)
	{
		m_Scale += 0.02 *event->delta() / 120;
	}
	else
	{
		if (event->delta() > 0)
		{
			m_Scale += 0.02 *event->delta() / 120;
		}
	}
	update();
}

 

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值