要转换的灰度图:
转换后的效果:
颜色翻转后的效果:
代码实现:
使用到的头文件:
#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();
}