计算机图形学实验课 HNUST (2025)
0.配置基本环境
1.配置OpenGL
使用CLion来开发OpenGL应用,下面是配置链接:
Clion配置Freeglut 【计算机图形学】(2025)-CSDN博客
2.配置OpenCV
使用PyCharm来开发OpenGL应用(你需要下载PyCharm),使用python开发会方便很多,下面是配置链接:
Python中cv2 (OpenCV, opencv-python)库的安装、使用方法demo最新详细教程_python cv2-CSDN博客
1.题目(一般是6选3)
实验1 OpenGL中的图形变换
1. 请使用OpenGL、GLU和GLUT编写一个显示线框立方体的程序。其中立方体的半径为1.5单位,并首先绕(0, 0, 0)~(1, 1, 0)旋转30度,然后远移6.5单位;观察体规定为:视场角=30度,宽高比=1,近=1,远=100;程序窗口的大小为(200, 200),标题为“线框立方体”。
#include "include/GL/freeglut.h"
void init() {
glClearColor(0.0, 0.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION); // 设置投影矩阵
glLoadIdentity(); // 重置当前矩阵为单位矩阵
gluPerspective(30.0, 1.0, 1.0, 100.0); // 设置透视投影,视场角=30度,宽高比=1,近=1,远=100
glMatrixMode(GL_MODELVIEW); // 设置模型视图矩阵
}
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清空颜色缓冲区和深度缓冲区
glLoadIdentity(); // 重置当前矩阵为单位矩阵
glTranslatef(0.0, 0.0, -6.5); // 远移6.5单位
glRotatef(30.0, 1.0, 1.0, 0.0); // 绕(1, 1, 0)旋转30度
glutWireCube(3.0); // 绘制线框立方体,半径为1.5
glFlush(); // 刷新绘图
}
void reshape(int w, int h) {
glViewport(0, 0, (GLsizei)w, (GLsizei)h); // 设置视口
glMatrixMode(GL_PROJECTION); // 设置投影矩阵
glLoadIdentity(); // 重置当前矩阵为单位矩阵
if (w <= h) {
glOrtho(-3.0, 3.0, -3.0 * (GLfloat)h / (GLfloat)w, 3.0 * (GLfloat)h / (GLfloat)w, -10.0, 10.0);
}
else {
glOrtho(-3.0 * (GLfloat)w / (GLfloat)h, 3.0 * (GLfloat)w / (GLfloat)h, -3.0, 3.0, -10.0, 10.0);
}
glMatrixMode(GL_MODELVIEW); // 设置模型视图矩阵
}
int main(int argc, char **argv) {
glutInit(&argc, argv); // 初始化GLUT库
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); // 设置显示模式:单缓冲、RGB颜色模型
int screen_width = glutGet(GLUT_SCREEN_WIDTH);
int screen_height = glutGet(GLUT_SCREEN_HEIGHT);
// 计算窗口的起始位置使其居中
int window_width = 800;
int window_height = 500;
int window_x = (screen_width - window_width) / 2;
int window_y = (screen_height - window_height) / 2;
// 设置窗口大小
glutInitWindowSize(window_width, window_height);
// 设置窗口位置
glutInitWindowPosition(window_x, window_y);
glutCreateWindow("OpenGL"); // 创建窗口并设置标题
init(); // 调用初始化函数
glutDisplayFunc(display); // 设置显示回调函数
glutReshapeFunc(reshape); // 设置重绘回调函数
glutMainLoop(); // 进入GLUT事件处理循环
return 0;
}

2. 请使用OpenGL和GLUT编写一个显示线框球体的简单图形程序。其中球体的半径为0.8,经线数为24,纬线数为12,并绕x 轴旋转30度,程序窗口的大小为(200, 200),标题为“线框球”。
#include "include/GL/freeglut.h"
void init() {
glClearColor(0.0, 0.0, 0.0, 0.0); // 设置背景颜色为黑色
glShadeModel(GL_FLAT); // 设置着色模式为平面着色
}
void display() {
glClear(GL_COLOR_BUFFER_BIT); // 清除颜色缓冲区
glPushMatrix(); // 保存当前模型视图矩阵
glRotatef(30.0, 1.0, 0.0, 0.0); // 绕x轴旋转30度
glColor3f(1.0, 1.0, 1.0); // 设置颜色为白色
glutWireSphere(0.8, 24, 12); // 绘制线框球体,半径为0.8,经线数为24,纬线数为12
glPopMatrix(); // 恢复之前保存的模型视图矩阵
glFlush(); // 刷新绘图
}
void reshape(int w, int h) {
glViewport(0, 0, (GLsizei)w, (GLsizei)h); // 设置视口
glMatrixMode(GL_PROJECTION); // 设置投影矩阵
glLoadIdentity(); // 重置当前矩阵为单位矩阵
if (w <= h) {
gluPerspective(60.0, (GLfloat)h / (GLfloat)w, 1.0, 20.0); // 根据宽高比设置透视投影
}
else {
gluPerspective(60.0, (GLfloat)w / (GLfloat)h, 1.0, 20.0); // 根据宽高比设置透视投影
}
glMatrixMode(GL_MODELVIEW); // 设置模型视图矩阵
glLoadIdentity(); // 重置当前矩阵为单位矩阵
glTranslatef(0.0, 0.0, -5.0); // 平移5个单位到观察点
}
int main(int argc, char **argv) {
glutInit(&argc, argv); // 初始化GLUT库
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); // 设置显示模式:单缓冲、RGB颜色模型
int screen_width = glutGet(GLUT_SCREEN_WIDTH);
int screen_height = glutGet(GLUT_SCREEN_HEIGHT);
// 计算窗口的起始位置使其居中
int window_width = 500;
int window_height = 500;
int window_x = (screen_width - window_width) / 2;
int window_y = (screen_height - window_height) / 2;
// 设置窗口大小
glutInitWindowSize(window_width, window_height);
// 设置窗口位置
glutInitWindowPosition(window_x, window_y);
glutCreateWindow("OpenGL 简单示例"); // 创建窗口并设置标题
init(); // 调用初始化函数
glutDisplayFunc(display); // 设置显示回调函数
glutReshapeFunc(reshape); // 设置重绘回调函数
glutMainLoop(); // 进入GLUT事件处理循环
return 0;
}

3. 请使用OpenGL和GLUT编写一个显示线框椭球体的简单图形程序。其中椭球体的两极方向为上下方向,左右方向的半径为0.98,上下方向的半径为0.49,前后方向的半径为0.6,经线数为48,纬线数为24,使用正投影,裁剪窗口为(-1, -0.5)~(1, 0.5),程序窗口的大小为(400, 200),标题为“线框椭球”。
#include <GL/glut.h>
#include <cmath>
// 椭球体的参数
#define LAT_SLICES 24
#define LON_SLICES 48
#define RADIUS_X 0.98
#define RADIUS_Y 0.49
#define RADIUS_Z 0.6
// 绘制椭球体的函数
void drawEllipsoid() {
int i, j;
for (i = 0; i < LON_SLICES; i++) {
glBegin(GL_LINE_LOOP);
for (j = 0; j <= LAT_SLICES; j++) {
double lat = j * (M_PI / (double)LAT_SLICES) - M_PI_2;
double lon = i * (2 * M_PI / (double)LON_SLICES) - M_PI;
double x = RADIUS_X * cos(lat) * cos(lon);
double y = RADIUS_Y * sin(lat);
double z = RADIUS_Z * cos(lat) * sin(lon);
glVertex3d(x, y, z);
}
glEnd();
}
for (i = 0; i < LAT_SLICES; i++) {
glBegin(GL_LINE_STRIP);
for (j = 0; j <= LON_SLICES; j++) {
double lat = i * (M_PI / (double)LAT_SLICES) - M_PI_2;
double lon = j * (2 * M_PI / (double)LON_SLICES) - M_PI;
double x = RADIUS_X * cos(lat) * cos(lon);
double y = RADIUS_Y * sin(lat);
double z = RADIUS_Z * cos(lat) * sin(lon);
glVertex3d(x, y, z);
}
glEnd();
}
}
// 显示回调函数
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 设置投影矩阵
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 1.0, -0.5, 0.5, -1.0, 1.0);
// 设置模型视图矩阵
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// 绘制椭球体
drawEllipsoid();
// 交换前后缓冲区
glutSwapBuffers();
}
// 初始化OpenGL状态
void init() {
// 设置背景颜色
glClearColor(0.0, 0.0, 0.0, 1.0);
// 启用深度测试
glEnable(GL_DEPTH_TEST);
// 设置线宽
glLineWidth(1.0);
}
int main(int argc, char** argv) {
// 初始化GLUT库
glutInit(&argc, argv);
// 设置显示模式:单缓冲、RGB颜色模型
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
int screen_width = glutGet(GLUT_SCREEN_WIDTH);
int screen_height = glutGet(GLUT_SCREEN_HEIGHT);
// 计算窗口的起始位置使其居中
int window_width = 400;
int window_height = 200;
int window_x = (screen_width - window_width) / 2;
int window_y = (screen_height - window_height) / 2;
// 设置窗口大小
glutInitWindowSize(window_width, window_height);
// 设置窗口位置
glutInitWindowPosition(window_x, window_y);
// 创建窗口
glutCreateWindow("线框椭球");
// 初始化OpenGL状态
init();
// 设置显示回调函数
glutDisplayFunc(display);
// 进入GLUT事件处理循环
glutMainLoop();
return 0;
}

4. 请使用OpenGL、GLU和GLUT编写一个三维犹他茶壶程序。其中茶壶的半径为1单位,并远移6.5单位;观察体规定为:视场角=30度,宽高比=1,近=1,远=100;程序窗口的大小为(200, 200),标题为“旋转的尤他茶壶”。茶壶绕z方向中轴不断旋转,旋转的时间间隔为25毫秒,角度间隔为2度。注意旋转角度必须限定在0~360度以内。
#include "include/GL/freeglut.h"
static int angle = 0; // 初始旋转角度为0
void init() {
glClearColor(0.0, 0.0, 0.0, 0.0); // 设置背景颜色为黑色
glShadeModel(GL_FLAT); // 设置着色模式为平面着色
}
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除颜色缓冲区和深度缓冲区
glColor3f(1.0, 1.0, 1.0); // 设置颜色为白色
glLoadIdentity(); // 重置当前的模型视图矩阵
gluLookAt(0.0, 0.0, 6.5, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); // 设置观察体
glRotatef((GLfloat)angle, 0.0, 0.0, 1.0); // 绕z轴旋转茶壶
glutWireTeapot(1.0); // 绘制茶壶
glutSwapBuffers(); // 交换前后缓冲区
}
void reshape(int w, int h) {
glViewport(0, 0, (GLsizei)w, (GLsizei)h); // 设置视口
glMatrixMode(GL_PROJECTION); // 设置当前矩阵为投影矩阵
glLoadIdentity(); // 重置当前的投影矩阵
gluPerspective(30.0, 1.0, 1.0, 100.0); // 设置透视投影参数
glMatrixMode(GL_MODELVIEW); // 设置当前矩阵为模型视图矩阵
}
void timer(int value) {
angle = (angle + 2) % 360; // 更新旋转角度
glutPostRedisplay(); // 标记窗口需要重新绘制
glutTimerFunc(25, timer, 0); // 25毫秒后再次调用timer函数
}
int main(int argc, char **argv) {
glutInit(&argc, argv); // 初始化GLUT库
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); // 设置显示模式:单缓冲、RGB颜色模型
int screen_width = glutGet(GLUT_SCREEN_WIDTH);
int screen_height = glutGet(GLUT_SCREEN_HEIGHT);
// 计算窗口的起始位置使其居中
int window_width = 500;
int window_height = 500;
int window_x = (screen_width - window_width) / 2;
int window_y = (screen_height - window_height) / 2;
// 设置窗口大小
glutInitWindowSize(window_width, window_height);
// 设置窗口位置
glutInitWindowPosition(window_x, window_y);
glutCreateWindow("OpenGL 简单示例"); // 创建窗口并设置标题
init(); // 调用初始化函数
glutDisplayFunc(display); // 设置显示回调函数
glutReshapeFunc(reshape); // 设置重绘回调函数
glutMainLoop(); // 进入GLUT事件处理循环
return 0;
}

5. 请使用OpenGL、GLU和GLUT编写一个多视口演示程序。要求:(1)在屏幕窗口左下角的1/4部分显示一个红色的填充矩形,该矩形的一对对角顶点是(0, 0)和(1, 1);(2)在屏幕窗口右下角的1/4部分显示一个绿色的填充犹他茶壶,茶壶半径为0.4,并向右向上各移0.5;(3)在屏幕窗口上部居中的1/4部分显示一个蓝色的填充正三角形,该正三角形的左下角顶点是(0,0),右下角顶点是(1, 0);(4)裁剪窗口均为(-0.1, -0.1)~(1.1, 1.1),程序窗口的大小为(200,200),背景为黑色,标题为“多视口演示”。
#include <GL/glut.h>
void init() {
glClearColor(0.0, 0.0, 0.0, 0.0); // 设置背景颜色为黑色
glShadeModel(GL_FLAT); // 设置着色模式为平面着色
}
void display() {
glClear(GL_COLOR_BUFFER_BIT); // 清除颜色缓冲区
// 左下角的红色填充矩形
glViewport(0, 0, 100, 100);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 1.0, 0.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor3f(1.0, 0.0, 0.0);
glBegin(GL_POLYGON);
glVertex2f(0.0, 0.0);
glVertex2f(1.0, 0.0);
glVertex2f(1.0, 1.0);
glVertex2f(0.0, 1.0);
glEnd();
// 右下角的绿色填充犹他茶壶
glViewport(100, 0, 100, 100);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-0.1, 1.1, -0.1, 1.1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.5, 0.5, 0.0);
glColor3f(0.0, 1.0, 0.0);
glutSolidTeapot(0.4);
// 上部居中的蓝色填充正三角形
glViewport(50, 100, 100, 100);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 1.0, 0.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor3f(0.0, 0.0, 1.0);
glBegin(GL_POLYGON);
glVertex2f(0.5, 1.0);
glVertex2f(1.0, 0.0);
glVertex2f(0.0, 0.0);
glEnd();
glutSwapBuffers(); // 交换前后缓冲区
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
// 获取屏幕宽度和高度
int screen_width = glutGet(GLUT_SCREEN_WIDTH);
int screen_height = glutGet(GLUT_SCREEN_HEIGHT);
// 计算窗口的起始位置使其居中
int window_width = 200;
int window_height = 200;
int window_x = (screen_width - window_width) / 2;
int window_y = (screen_height - window_height) / 2;
// 设置窗口大小
glutInitWindowSize(window_width, window_height);
// 设置窗口位置
glutInitWindowPosition(window_x, window_y);
glutCreateWindow("White Sphere with Lighting");
init();
glutDisplayFunc(display);
glutMainLoop();
return 0;
}

实验2 OpenGL的真实感图形
6. 使用OpenGL和GLUT编写一个程序,用于模拟一个非常光滑的纯白球面在烈日暴晒下的效果。
#include <GL/glut.h>
// 初始化光照和材质属性
void initLighting() {
glEnable(GL_DEPTH_TEST); // 启用深度测试
// 环境光(不考虑环境光,所以设置为0)
GLfloat ambientLight[] = {0.0, 0.0, 0.0, 1.0};
// 点光源的漫反射光
GLfloat diffuseLight[] = {1.0, 1.0, 1.0, 1.0}; // 白色光
// 点光源的位置
GLfloat lightPos[] = {1.0, 1.0, 1.0, 0.0}; // 右上角方向
// 光源属性
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
// 启用光源0和光照模型
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
// 设置材质属性
GLfloat mat_ambient[] = {0.2, 0.0, 0.6, 1.0}; // 紫色
GLfloat mat_diffuse[] = {0.2, 0.0, 0.6, 1.0}; // 紫色
GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0}; // 镜面反射为白色
GLfloat mat_shininess[] = {50.0}; // 光泽度
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
}
// 绘制球体
void drawSphere() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glutSolidSphere(1.0, 20, 20); // 绘制半径为1的球体
}
// 显示回调函数
void display() {
initLighting();
drawSphere();
glutSwapBuffers();
}
// 窗口重绘回调函数
void reshape(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat)w / (GLfloat)h, 1.0, 20.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 0.0, 5.0, // 眼睛位置
0.0, 0.0, 0.0, // 观察点
0.0, 1.0, 0.0); // 上方向
}
// 主函数
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
int screen_width = glutGet(GLUT_SCREEN_WIDTH);
int screen_height = glutGet(GLUT_SCREEN_HEIGHT);
// 计算窗口的起始位置使其居中
int window_width = 500;
int window_height = 500;
int window_x = (screen_width - window_width) / 2;
int window_y = (screen_height - window_height) / 2;
// 设置窗口大小
glutInitWindowSize(window_width, window_height);
// 设置窗口位置
glutInitWindowPosition(window_x, window_y);
glutCreateWindow("光照效果演示");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}

7. 已知在一个空旷的场景中有一个粗糙的紫色球体,球体的右上角方向放置了一个白色的点光源,请使用OpenGL和GLUT编写一个程序模拟出球面上的光照效果(不考虑环境光)。
#include <GL/glut.h>
// 初始化光照和材质属性
void initLighting() {
glEnable(GL_DEPTH_TEST); // 启用深度测试
// 环境光(不考虑环境光,所以设置为0)
GLfloat ambientLight[] = {0.0, 0.0, 0.0, 1.0};
// 点光源的漫反射光
GLfloat diffuseLight[] = {1.0, 1.0, 1.0, 1.0}; // 白色光
// 点光源的位置
GLfloat lightPos[] = {1.0, 1.0, 1.0, 0.0}; // 右上角方向
// 光源属性
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
// 启用光源0和光照模型
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
// 设置材质属性
GLfloat mat_ambient[] = {0.2, 0.0, 0.6, 1.0}; // 紫色
GLfloat mat_diffuse[] = {0.2, 0.0, 0.6, 1.0}; // 紫色
GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0}; // 镜面反射为白色
GLfloat mat_shininess[] = {50.0}; // 光泽度
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
}
// 绘制球体
void drawSphere() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glutSolidSphere(1.0, 20, 20); // 绘制半径为1的球体
}
// 显示回调函数
void display() {
initLighting();
drawSphere();
glutSwapBuffers();
}
// 窗口重绘回调函数
void reshape(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat)w / (GLfloat)h, 1.0, 20.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 0.0, 5.0, // 眼睛位置
0.0, 0.0, 0.0, // 观察点
0.0, 1.0, 0.0); // 上方向
}
// 主函数
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
int screen_width = glutGet(GLUT_SCREEN_WIDTH);
int screen_height = glutGet(GLUT_SCREEN_HEIGHT);
// 计算窗口的起始位置使其居中
int window_width = 500;
int window_height = 500;
int window_x = (screen_width - window_width) / 2;
int window_y = (screen_height - window_height) / 2;
// 设置窗口大小
glutInitWindowSize(window_width, window_height);
// 设置窗口位置
glutInitWindowPosition(window_x, window_y);
glutCreateWindow("光照效果演示");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}

实验3 OpenCV核心功能
8. 请根据BMP文件的格式编写一个C++函数vector<uchar> loadBmp24(const string &path)。该函数用于从一个真彩色BMP文件中读取图像数据,保存在uchar数组中(可以忽略非真彩色BMP文件)。
import struct
def load_bmp24(path):
with open(path, 'rb') as f:
# 读取BMP文件头 (14字节)
file_header = f.read(14)
file_type, file_size, reserved1, reserved2, offset = struct.unpack('<2sIHHI', file_header)
# 确保是BMP文件
if file_type != b'BM':
raise ValueError("Not a BMP file")
# 定位到DIB头开始位置 (偏移量 - 文件头大小)
f.seek(offset - 14)
# 读取DIB头 (40字节)
dib_header = f.read(40)
if len(dib_header) != 40:
raise ValueError("DIB header is not 40 bytes long")
# 解析DIB头
header_size, width, height, planes, bit_count, compression, size_image, x_pixels_per_meter, y_pixels_per_meter, colors_used, colors_important = struct.unpack(
'<IiiHHIIIIII', dib_header)
print(height)
# 确保是24位不压缩的BMP文件
if bit_count != 24 or compression != 0:
raise ValueError("Not a 24-bit uncompressed BMP file")
# 每行字节数,填充到4字节边界
row_size = (width * 3 + 3) & ~3
# 定位到像素数据开始位置
f.seek(offset)
# 读取像素数据
image_data = f.read(row_size * abs(height)) # 使用abs(height)处理BMP文件的上下顺序
# 转换为字节列表并返回
return bytearray(image_data)
# 使用示例
# 替换以下路径为你的BMP文件的实际路径
path = "\\Computer_Graphics\\Experiment_2024_12_02\\picture.bmp"
image_data = load_bmp24(path)
print(image_data)
9. 使用OpenCV装入一幅大小至少为512×512的真彩色图像,并显示该图像。然后在源图像中指定一个矩形区域(左上顶点和宽高值分别为(128, 256)和(256, 128)的矩形),并在结果图像窗口中显示源图像中被选取的部分。
import cv2
import numpy as np
path = "\\Computer_Graphics\\Experiment_2024_12_02\\picture.jpg"
# 读取图像
image = cv2.imread(path)
# 检查图像是否被正确加载
if image is None:
print("图像加载失败,请检查路径!")
else:
# 显示原始图像
cv2.imshow('Original Image', image)
cv2.waitKey(0) # 等待按键
# 定义矩形区域的左上顶点和宽高
top_left_x = 128
top_left_y = 256
width = 256
height = 128
# 裁剪图像
cropped_image = image[top_left_y:top_left_y+height, top_left_x:top_left_x+width]
# 显示裁剪后的图像
cv2.imshow('Cropped Image', cropped_image)
cv2.waitKey(0) # 等待按键
# 关闭所有OpenCV窗口
cv2.destroyAllWindows()

10. 请使用OpenCV编写一个简单的程序,该程序首先读入一幅真彩色图像,然后将这幅彩色图像的3个通道分离出来,得到3幅灰度图像,最后显示这3幅灰度图像。
import cv2
import numpy as np
path = "D:\\Computer_Graphics\\Experiment_2024_12_02\\picture.jpg"
# 读取图像
image = cv2.imread(path) # 替换为你的图像路径
# 检查图像是否被正确加载
if image is None:
print("图像加载失败,请检查路径!")
else:
# 分离颜色通道
B, G, R = cv2.split(image)
# 垂直拼接三个通道
# 首先确保三个通道的宽度相同,这里我们取图像的原始宽度
height, width, _ = image.shape
B = cv2.resize(B, (width//2, height//2)) # 调整高度以适应垂直拼接
G = cv2.resize(G, (width//2, height//2)) # 调整高度以适应垂直拼接
R = cv2.resize(R, (width//2, height//2)) # 调整高度以适应垂直拼接
concatenated_image = np.vstack((B, G, R)) # 垂直拼接
# 显示拼接后的图像
cv2.imshow('Concatenated Channels', concatenated_image)
# 等待按键
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()

11. 首先使用OpenCV装入一幅灰度图像并显示该图像,然后计算出该图像的最小像素值min和最大像素值max,最后将每个像素都减去min再乘以255/max以后显示结果图像。
import cv2
import numpy as np
path = "picture.jpg"
gray_image = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
# 计算最小像素值和最大像素值
min_pixel = np.min(gray_image)
max_pixel = np.max(gray_image)
# 对每个像素进行处理
processed_image = (gray_image - min_pixel) * (255 / (max_pixel - min_pixel))
processed_image = np.clip(processed_image, 0, 255).astype(np.uint8)
processed= np.vstack((gray_image, processed_image)) # 垂直拼接
# 显示处理后的图像
cv2.imshow('Processed Image', processed)
cv2.waitKey(0)
# 退出并销毁所有窗口
cv2.destroyAllWindows()

12. 随机生成一幅浮点数灰度图像(大小和亮度都是随机的,大小值位于区间[128, 639]),然后将该图像变换成亮度是0~1的浮点数图像,最后变换成字节图像并显示该图像。
import cv2
import numpy as np
# 设置随机种子以获得可重复的结果
np.random.seed(0)
# 随机生成一幅浮点数灰度图像,大小值位于区间[128, 639]
# 假设图像大小为512x512,可以根据需要调整
image_size = (512, 512)
random_float_image = np.random.randint(128, 640, size=image_size).astype(np.float32)
# 显示原始浮点数灰度图像
cv2.imshow('Random Float Image', random_float_image / 639.0) # 先归一化到[0, 1]区间
cv2.waitKey(0)
# 将浮点数灰度图像变换成亮度是0~1的浮点数图像
normalized_float_image = random_float_image / 639.0
# 将浮点数图像变换成字节图像
byte_image = (normalized_float_image * 255).astype(np.uint8)
# 显示字节图像
cv2.imshow('Byte Image', byte_image)
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()

实验4 图像变换
13. 使用OpenCV编写一个演示对原图像进行缩放变换的程序。该程序首先装入一幅真彩色图像并显示该图像,然后对该图像进行缩放变换,显示得到的结果。其中旋转中心位于图像中心,缩放系数为(0.707, 0.707),旋转角度为45度。
import cv2
import numpy as np
path = "\\Computer_Graphics\\Experiment_2024_12_02\\picture.jpg"
image = cv2.imread(path)
# 检查图像是否被正确加载
if image is None:
print("图像加载失败,请检查路径!")
else:
# 获取图像尺寸
(h, w) = image.shape[:2]
# 计算旋转中心
center = (w // 2, h // 2)
# 计算旋转矩阵
M = cv2.getRotationMatrix2D(center, 45, 0.707)
# 进行缩放变换
scaled_rotated_image = cv2.warpAffine(image, M, (w, h))
# 显示缩放变换后的图像
cv2.imshow('Scaled and Rotated Image', scaled_rotated_image)
# 等待按键
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()

14. 使用OpenCV编写一个演示傅立叶变换和逆变换的程序。该程序首先装入一幅灰度图像并显示该图像,然后对该图像进行傅立叶正变换,对得到的结果进行傅立叶逆变换,显示得到的结果以便与原图像进行比对。
import cv2
import numpy as np
# 读取灰度图像
path = "\\picture.jpg"
image = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
# 检查图像是否被正确加载
if image is None:
print("图像加载失败,请检查路径!")
else:
# 显示原始灰度图像
cv2.imshow('Original Grayscale Image', image)
# 进行傅立叶变换
dft = cv2.dft(np.float32(image), flags=cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
# 显示傅立叶变换的结果(显示幅度谱)
magnitude_spectrum = 20 * np.log(cv2.magnitude(dft_shift[:, :, 0], dft_shift[:, :, 1]))
magnitude_spectrum = np.uint8(magnitude_spectrum / np.max(magnitude_spectrum) * 255) # 归一化到0-255范围
cv2.imshow('Magnitude Spectrum', magnitude_spectrum)
# 进行傅立叶逆变换
idft_shift = np.fft.ifftshift(dft_shift)
img_back = cv2.idft(idft_shift)
img_back = cv2.magnitude(img_back[:, :, 0], img_back[:, :, 1])
# 显示傅立叶逆变换的结果
cv2.imshow('Image after Inverse DFT', img_back)
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()

15. 请为OpenCV提供一个中心化函数FFTShift,该函数的函数原型为“Mat FFTShift(Mat X);”。
import cv2
import numpy as np
def FFTShift(X):
"""
中心化FFT结果的函数。
参数:
X -- cv2.Mat对象,即输入的矩阵。
返回:
中心化后的矩阵。
"""
# 获取矩阵的维度
rows, cols = X.shape[:2]
# 计算中心点
crow, ccol = rows // 2, cols // 2
# 从中心点分割矩阵
top = X[:crow, :]
bottom = X[crow:, :]
left = X[:, :ccol]
right = X[:, ccol:]
# 重新组合矩阵,使其中心化
shifted = np.concatenate((bottom, top), axis=0)
shifted = np.concatenate((right, left), axis=1)
return shifted
# 使用示例
# 读取图像并转换为灰度
path = "picture.jpg"
image = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
# 检查图像是否被正确加载
if image is None:
print("图像加载失败,请检查路径!")
else:
# 进行傅立叶变换
dft = cv2.dft(np.float32(image), flags=cv2.DFT_COMPLEX_OUTPUT)
# 应用中心化FFTShift
dft_shift = FFTShift(dft)
# 计算幅度谱
magnitude_spectrum = 20 * np.log(cv2.magnitude(dft_shift[:, :, 0], dft_shift[:, :, 1]))
# 归一化到0-255范围
magnitude_spectrum = cv2.normalize(magnitude_spectrum, None, 0, 255, cv2.NORM_MINMAX)
# 转换为uint8类型
magnitude_spectrum = magnitude_spectrum.astype(np.uint8)
# 显示中心化后的幅度谱
cv2.imshow('Magnitude Spectrum', magnitude_spectrum)
cv2.waitKey(0)
cv2.destroyAllWindows()

实验5 图像增强
16. 使用OpenCV编写一个程序,该程序对一幅彩色图像进行一次中值模糊,要求分别显示源图像和模糊化以后的图像。其中内核大小为5×5。
import cv2
path = "picture.jpg"
image = cv2.imread(path)
# 检查图像是否被正确加载
if image is None:
print("图像加载失败,请检查路径!")
else:
# 显示源图像
cv2.imshow('Source Image', image)
# 对图像进行中值模糊,内核大小为5x5
blurred_image = cv2.medianBlur(image, 5)
# 显示模糊后的图像
cv2.imshow('Blurred Image', blurred_image)
# 等待按键
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()

17. 使用OpenCV编写一个程序,该程序对一幅灰度图像进行Sobel锐化,要求显示锐化以后的图像。其中内核大小为3×3,x和y方向均使用1阶差分。
import cv2
import numpy as np
path = "picture.jpg"
image = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
# 检查图像是否被正确加载
if image is None:
print("图像加载失败,请检查路径!")
else:
# 使用Sobel算子进行x方向和y方向的1阶差分
sobelx = cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize=3)
sobely = cv2.Sobel(image, cv2.CV_64F, 0, 1, ksize=3)
# 计算梯度的幅度
sobel_grad = cv2.magnitude(sobelx, sobely)
# 将梯度幅度归一化到0-255范围
sobel_grad = np.uint8(sobel_grad / np.max(sobel_grad) * 255)
# 将梯度幅度加到原图像上进行锐化
sharpened_image = cv2.add(image, sobel_grad)
# 显示锐化后的图像
cv2.imshow('Sharpened Image', sharpened_image)
# 等待按键
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()

18. 使用OpenCV编写一个程序,该程序对一幅灰度图像进行Laplace锐化,要求显示锐化以后的图像。其中内核大小为3×3。
import cv2
import numpy as np
path = "\\picture.jpg"
image = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
# 检查图像是否被正确加载
if image is None:
print("图像加载失败,请检查路径!")
else:
# 使用Laplace算子进行锐化,内核大小为3x3
laplace_kernel = np.array([[0, 1, 0],
[1, -4, 1],
[0, 1, 0]], dtype=np.float32) / 8 # 标准化内核
laplace = cv2.filter2D(image, -1, laplace_kernel)
# 将拉普拉斯结果转换为uint8类型
laplace = np.uint8(np.absolute(laplace))
# 将拉普拉斯结果加到原图像上进行锐化
sharpened_image = cv2.add(image, laplace)
# 显示锐化后的图像
cv2.imshow('Sharpened Image', sharpened_image)
# 等待按键
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()

19. 使用OpenCV编写一个程序,该程序使用大小为3的正方形模板(锚点位于模板中心)对源图像进行2次腐蚀操作,要求显示源图像和腐蚀以后的图像。
import cv2
import numpy as np
path = "D:\\picture.jpg"
image = cv2.imread(path)
# 检查图像是否被正确加载
if image is None:
print("图像加载失败,请检查路径!")
else:
# 显示源图像
cv2.imshow('Original Image', image)
# 定义3x3正方形模板,锚点位于中心
kernel = np.ones((3, 3), np.uint8)
# 对图像进行第一次腐蚀操作
erosion1 = cv2.erode(image, kernel, iterations=1)
# 对图像进行第二次腐蚀操作
erosion2 = cv2.erode(erosion1, kernel, iterations=1)
# 显示腐蚀后的图像
cv2.imshow('Eroded Image after 2 iterations', erosion2)
# 等待按键
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()

20. 使用OpenCV编写一个程序,该程序对一幅灰度图像进行一次2阶指数低通滤波,其中截止频率为20,要求分别显示源图像和滤波以后的图像。
import cv2
import numpy as np
def butterworth_lowpass_filter(image, k, n):
"""
对图像应用n阶巴特沃斯低通滤波器。
参数:
image -- 输入的灰度图像。
k -- 截止频率。
n -- 滤波器的阶数。
返回:
滤波后的图像。
"""
# 获取图像尺寸
M, N = image.shape
# 创建距离矩阵D(u, v)
u = np.tile(np.arange(N), (M, 1))
v = np.tile(np.arange(M), (N, 1)).T
D = np.sqrt(u ** 2 + v ** 2)
# 创建巴特沃斯低通滤波器
H = 1 / (1 + (D / k) ** (2 * n))
# 将滤波器应用于图像的傅立叶变换
dft = cv2.dft(np.float32(image), flags=cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
# 应用滤波器到复数的实部和虚部
fshift = dft_shift.copy()
fshift[:, :, 0] *= H # 实部
fshift[:, :, 1] *= H # 虚部
# 应用逆傅立叶变换
f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
# 计算幅度
img_back = cv2.magnitude(img_back[:, :, 0], img_back[:, :, 1])
# 归一化到0-255范围
img_back = np.uint8(img_back / np.max(img_back) * 255)
return img_back
path = "\\picture.jpg"
image = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
# 检查图像是否被正确加载
if image is None:
print("图像加载失败,请检查路径!")
else:
# 显示源图像
cv2.imshow('Original Image', image)
# 对图像进行2阶指数低通滤波,截止频率为20
filtered_image = butterworth_lowpass_filter(image, k=20, n=2)
# 显示滤波后的图像
cv2.imshow('Filtered Image', filtered_image)
# 等待按键
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()

21. 使用OpenCV编写一个程序,该程序对一幅灰度图像进行一次2阶指数高通滤波,其中截止频率为45,要求分别显示源图像和滤波以后的图像。
import cv2
import numpy as np
def butterworth_highpass_filter(image, k, n):
"""
对图像应用n阶巴特沃斯高通滤波器。
参数:
image -- 输入的灰度图像。
k -- 截止频率。
n -- 滤波器的阶数。
返回:
滤波后的图像。
"""
# 获取图像尺寸
M, N = image.shape
# 创建距离矩阵D(u, v)
u = np.tile(np.arange(N), (M, 1))
v = np.tile(np.arange(M), (N, 1)).T
D = np.sqrt(u ** 2 + v ** 2)
# 创建巴特沃斯高通滤波器
H = 1 - 1 / (1 + (D / k) ** (2 * n))
# 将滤波器应用于图像的傅立叶变换
dft = cv2.dft(np.float32(image), flags=cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
# 应用滤波器到复数的实部和虚部
fshift = dft_shift.copy()
fshift[:, :, 0] *= H # 实部
fshift[:, :, 1] *= H # 虚部
# 应用逆傅立叶变换
f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
# 计算幅度
img_back = cv2.magnitude(img_back[:, :, 0], img_back[:, :, 1])
# 归一化到0-255范围
img_back = np.uint8(img_back / np.max(img_back) * 255)
return img_back
path = "D:\picture.jpg"
image = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
# 检查图像是否被正确加载
if image is None:
print("图像加载失败,请检查路径!")
else:
# 显示源图像
cv2.imshow('Original Image', image)
# 对图像进行2阶指数高通滤波,截止频率为45
filtered_image = butterworth_highpass_filter(image, k=45, n=2)
# 显示滤波后的图像
cv2.imshow('Filtered Image', filtered_image)
# 等待按键
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()

实验6 图像解析
22. 使用OpenCV编写一个程序,该程序对一幅灰度图像进行二值化变换,要求分别显示源图像和二值化以后的图像。其中二值化阈值为127,高亮度改为255。

import cv2
# 读取灰度图像
image = cv2.imread('path_to_your_image.jpg', cv2.IMREAD_GRAYSCALE) # 替换为你的图像路径
# 检查图像是否被正确加载
if image is None:
print("图像加载失败,请检查路径!")
else:
# 显示源图像
cv2.imshow('Original Image', image)
# 进行二值化变换,阈值为127,高亮度改为255
_, binary_image = cv2.threshold(image, 127, 255, cv2.THRESH_BINARY)
# 显示二值化后的图像
cv2.imshow('Binary Image', binary_image)
# 等待按键
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()
23. 使用OpenCV编写一个程序,该程序对一幅灰度图像进行Canny边缘检测,要求分别显示源图像和检测到的边缘。其中小阈值为50,大阈值为150,内核大小为3。

import cv2
# 读取灰度图像
image = cv2.imread('path_to_your_image.jpg', cv2.IMREAD_GRAYSCALE) # 替换为你的图像路径
# 检查图像是否被正确加载
if image is None:
print("图像加载失败,请检查路径!")
else:
# 显示源图像
cv2.imshow('Original Image', image)
# 进行Canny边缘检测,小阈值为50,大阈值为150,内核大小为3
edges = cv2.Canny(image, 50, 150, apertureSize=3)
# 显示检测到的边缘
cv2.imshow('Edges Detected', edges)
# 等待按键
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()
24. 使用OpenCV编写一个程序,该程序首先使用Canny算法检测边缘,然后从源图像中复制出边缘像素。注意,源图像是彩色图像,边缘检测时需转换成灰度图像,结果图像也是彩色图像。

import cv2
import numpy as np
path = "picture.jpg"
# 读取彩色源图像
color_image = cv2.imread(path) # 替换为你的图像路径
# 检查图像是否被正确加载
if color_image is None:
print("图像加载失败,请检查路径!")
else:
# 显示源图像
cv2.imshow('Original Color Image', color_image)
# 将彩色图像转换为灰度图像
gray_image = cv2.cvtColor(color_image, cv2.COLOR_BGR2GRAY)
# 使用Canny算法检测边缘,小阈值为50,大阈值为150,内核大小为3
edges = cv2.Canny(gray_image, 50, 150, apertureSize=3)
# 将边缘检测结果转换为三通道图像,以便与彩色图像进行操作
edges_color = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR)
# 从源图像中复制出边缘像素
# 我们将使用cv2.bitwise_and来逐通道进行操作
result_image = cv2.bitwise_and(color_image, edges_color)
# 显示结果图像
cv2.imshow('Result Image', result_image)
# 等待按键
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()
25. 使用OpenCV编写一个程序,该程序对一幅彩色图像(例如当前目录中的lena.jpg)使用指定的模板图像(例如当前目录中的Template.jpg)进行模板匹配。要求使用分别使用OpenCV支持的6种匹配算法分别进行模板匹配,源图像中与模板最匹配的区域分别使用一个指定颜色的矩形标记。

import cv2
import numpy as np
# 读取彩色源图像和模板图像
source_image = cv2.imread("picture.jpg") # 确保当前目录中有lena.jpg文件
template = cv2.imread("picture_temp.jpg", 0) # 确保当前目录中有template.jpg文件
cv2.imshow('Original Color Image', template)
# 检查图像是否被正确加载
if source_image is None or template is None:
print("图像加载失败,请检查路径!")
else:
# 将源图像转换为灰度图像
source_gray = cv2.cvtColor(source_image, cv2.COLOR_BGR2GRAY)
# 获取模板的高度和宽度
h, w = template.shape[:2]
# 遍历所有匹配方法
methods = [
("SQDIFF", cv2.TM_SQDIFF),
("SQDIFF_NORMED", cv2.TM_SQDIFF_NORMED),
("CCORR", cv2.TM_CCORR),
("CCORR_NORMED", cv2.TM_CCORR_NORMED),
("CCOEFF", cv2.TM_CCOEFF),
("CCOEFF_NORMED", cv2.TM_CCOEFF_NORMED)
]
for method_name, method_flag in methods:
# 应用模板匹配方法
result = cv2.matchTemplate(source_gray, template, method_flag)
# 找到最匹配的位置
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
# 计算最匹配区域的坐标
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
# 在源图像上标记最匹配的区域
match_image = source_image.copy()
cv2.rectangle(match_image, top_left, bottom_right, (0, 0, 255), 2)
# 显示匹配结果
cv2.imshow(f'{method_name} Match', match_image)
# 等待按键
cv2.waitKey(0)
cv2.destroyAllWindows()
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)