1、简述题(10分×4题,共40分)
2、计算题(共10分)
3、编程题(共30分)
4、问答题(共20分)
(1)第1章的基本内容
(2)三维观察流水线中的基本概念与理解
(3)三维场景真实感绘制中的基本概念与理解
(4)图像增强中的基本概念与理解
(5)形态学操作,包括膨胀,腐蚀,开,闭等操作中的基本概念与理解
Bézier样条的计算表达
(1)OpenCV基本函数的调用
(2)利用OpenGL编写核心代码,包括平移,旋转,缩放及坐标系之间的变换等所有其它的基本变换。
(3)利用OpenCV编写核心代码,内容包括图像增强,图像分析等
计算机图形学是研究怎样利用计算机表示、生成、处理和显示图形的原理、算法、方法和技术的一门学科(计算机图形学=造型+绘制)。
例如,方程x+y=1确定的图形由满足这个方程并具有一定颜色信息的点构成。
一般来说,在计算机中有下列两种表示图形的方法:
用图形的形状参数和属性参数来表示图形。
参数法描述的图形叫做参数图或简称为图形。
通过列出图形中所有的点来表示图形。点阵法强调的是:
点阵法描述的图形叫做像素图或图像。
如何开发和利用图形输入设备及相关软件把图形输入到计算机中,以便进行各种处理。
包括对图形进行变换(如几何变换、投影变换)和运算(如图形的并、交、差运算)等处理。
如何将图形的特定表示形式转换成图形输出系统便于接受的表示形式,并将图形在显示器或打印机等输出设备上输出。
(此部分可能出问答题,囿于篇幅,此处不详细展开,详细内容请移步教材P5-P7)
用T(tx,ty,tz)表示。
用S(sx,sy,sz)表示。
分别用Rx(θ)、Ry(θ)和Rz(θ)表示绕x轴、y轴和z轴的旋转。
表示绕旋转轴(0,0,0)—(x,y,z)旋转th角度。
已知P0={x0,y0,z0},P1={x1,y1,z1},旋转轴为P0P1,旋转角为θ。求该旋转变换的变换矩阵。
glTranslated(x0, y0, z0); // (5) 使旋转轴回到原来的位置
glMultMatrixd((const double[]){ // (4) 使旋转轴回到原来的方向
u1, u2, u3, 0,
v1, v2, v3, 0,
n1, n2, n3, 0,
0, 0, 0, 1
});
glRotated(th, 0, 0, 1); // (3) 绕坐标轴完成指定的旋转
glMultMatrixd((const double[]){ // (2) 使旋转轴与某坐标轴重合
u1, v1, n1, 0,
u2, v2, n2, 0,
u3, v3, n3, 0,
0, 0, 0, 1
});
glTranslated(-x0, -y0, -z0); // (1) 使旋转轴通过坐标原点
已知反射轴为P0P1,P0={x0,y0,z0},P1={x1,y1,z1}。求该反射变换的变换矩阵。
glTranslated(x0, y0, z0); // (5) 使反射轴回到原来的位置
glMultMatrixd((const double[]){ // (4) 使反射轴回到原来的方向
u1, u2, u3, 0,
v1, v2, v3, 0,
n1, n2, n3, 0,
0, 0, 0, 1
});
glScaled(-1, -1, 1); // (3) 关于坐标轴完成指定的反射
glMultMatrixd((const double[]){ // (2) 使反射轴与某坐标轴重合
u1, v1, n1, 0,
u2, v2, n2, 0,
u3, v3, n3, 0,
0, 0, 0, 1
});
glTranslated(-x0, -y0, -z0); // (1) 使反射轴通过坐标原点
已知反射面的方程为ax+by+cz+d=0 ,且点(x0,y0,z0)在反射面上。求该反射变换的变换矩阵。
glTranslated(x0, y0, z0); // (5) 使反射面回到原来的位置
glMultMatrixd((const double[]){ // (4) 使反射面回到原来的方向
u1, u2, u3, 0,
v1, v2, v3, 0,
n1, n2, n3, 0,
0, 0, 0, 1
});
glScaled(1, 1, -1); // (3) 关于坐标平面完成指定的反射
glMultMatrixd((const double[]){ // (2) 使反射面与某坐标平面重合
u1, v1, n1, 0,
u2, v2, n2, 0,
u3, v3, n3, 0,
0, 0, 0, 1
});
glTranslated(-x0, -y0, -z0); // (1) 使反射面通过坐标原点
(此处老师提到“基础概念、理解”)
可见面判别算法也可称为隐藏面消除算法,可以分为:
※ 此章老师说结合课程PPT和另外发的补充PPT复习,没有给出明确考点,因此将一些基本知识点整合至此。
数字图像处理的研究对象是数字图像。图像这个词包含的内容很广,凡是记录在纸上,拍摄在照片上,显示在屏幕上的所有具有视觉效果的画面都可以称为图像。
图像的灰度信息是指图像中各点处的颜色深浅程度信息(也就是明暗程度信息或亮度信息)。
(1)从视觉特点,分为可见图像和不可见图像。
(2)根据图像记录方式的不同,图像可分为两大类。
(3)数字图像的基本类型:
※ 数字图像处理的目的
数字图像在计算机上是以位图形式存在的。位图是一个矩形点阵,每一个点都称为一个像素。像素是数字图像中的基本单位。一幅W×H大小的图像,是由W×H个明暗不等的像素组成的。
基于调色板的BMP文件由文件头、信息头、调色板和图像的像素数据四个部分组成,而真彩色的BMP文件则由文件头、信息头和图像的BGR像素数据组成。
※ 这章老师说不明确考,也没有明确考点,因此根据基本概念和平时作业补充资料,仅供参考。
图像变换是对图像的像素位置或像素值进行的某种变换,主要内容通常包括对像素位置的变换、对单一像素的变换和对像素块的变换等方面。
图像的空间转换主要包括空域与空域的转换和空域与频域的转换等两类。
1、计算对下列实数矩阵进行傅立叶正变换后的变换结果(不缩放结果)。
2、计算对下列实数矩阵进行傅立叶逆变换后的变换结果(缩放结果,i为虚数单位)。
※ 此题给出个人答案,仅供参考,如有错误请联系指正(确信)
图像增强是图像处理的基础,它是对图像施加的某种数学变换,其目的通常是为了除去图像中的噪音,强调或抽取图像的轮廓特征等。
图像中的噪音是指在图像生成、保存和传递过程中由外部干扰在图像中加入的冗余信息。例如,电视画面上常见的雪花点就是一种典型的噪音。
图像增强有两类不同的基本技术:
平滑处理是一种简单且使用频率很高的图像处理方法,是除去图像中点状噪音的一个有效方法。
所谓平滑化,是指使图像上任何一个像素与其相邻像素的灰度值的大小不会出现陡变的一种处理方法。
这种处理会使得图像变模糊,所以图像的平滑化也称为图像的模糊化。
归一化块滤波器的特点是模板系数之和为1。模板系数全相同的归一化块滤波器称为均值模糊器或简单模糊器,是最简单的滤波器。
高斯滤波器是一种通过指定参数计算模板系数的归一化块滤波器,是最有用的滤波器(尽管不是最快的)。
中值滤波是一种非线性处理技术,可用来抑制图像中的噪音,而且保持轮廓的清晰。中值滤波使用当前像素近旁nx×ny个像素的灰度值的中值(不是平均值)作为当前像素的新灰度值,即
例如,Med{2,0,5,9,0,0,18,1,29}=2 。{2,0,5,9,0,0,18,1,29}排序后变成{0,0,0,1,2,5,9,18,29},容易看出,中值是第5号元素2。
※ 中值滤波具有不损失有效信息的优点。
※ 大概是有考编程的部分了。
【函数原型】void blur(InputArray src, OutputArray dst, Size ksize);
【参数】
【函数原型】void median(BlurInputArray src, OutputArray dst, int ksize);
【参数】
【函数原型】void GaussianBlur(InputArray src,OutputArray dst,Size ksize, double sigmaX, double sigmaY=0);
【参数】
【说明】如果sigmaY=0,则使用sigmaY=sigmaX。如果标准差都是0,则使用公式σ=0.3(0.5n-1)+0.8由内核尺寸计算标准差。
对一幅含有噪音的灰度图像进行简单模糊、中值模糊和高斯模糊:
#include
using namespace cv;
int main() {
Mat X = imread("lena-n.jpg", 0); // 含噪声的灰度图像
if(X.empty())
return -1;
imshow("源图像", X);
Mat Y; // 结果图像
blur(X, Y, {5, 5}); // 简单模糊
imshow("简单模糊", Y);
medianBlur(X, Y, 5); // 中值模糊
imshow("中值模糊", Y);
GaussianBlur(X, Y, {5, 5}, 0, 0); // 高斯模糊, 标准差都是0
imshow("高斯模糊", Y);
waitKey();
}
图像锐化处理的主要目的是突出图像中的细节或者增强被模糊化了的细节,一般情况下图像的锐化被用于景物边界的检测与提取,把景物的结构轮廓清晰地表现出来。使用锐化方法处理后的图像,轮廓线条将明显得到增强。轮廓线以外的部分将变得较暗,而轮廓线部分将变得比较明亮。
有时需要在图像中抽出某一特定方向的轮廓线,这时可以使用方向模板来达到这一目的。根据所需的方向,可从下列8种模板中选取合适的模板。
形态学操作也是一种非线性处理技术。简单来讲,形态学操作就是基于形状的一系列图像处理操作。通过将结构元素作用于输入图像来产生输出图像。结构元素就是矩形、椭圆等形状的模板,可以通过分别将形状部分的模板系数指定为1,其余部分的模板系数指定为0实现。
形态学操作运用广泛,如下列情形均可从形态学操作获益:
※ 主要把老师点的重点整理如下,此外还有3种高级形态学操作(形态学梯度、顶帽、黑帽)可以根据情况看教材了解。
先腐蚀再膨胀,用于在图像中消除小的物体,在纤细点处分离物体,在将较大物体的边界平滑化的同时不明显改变物体的体积。
先膨胀再腐蚀,能够排除小型黑洞,消除小块噪音区域,连接邻近区域。
※ 老师提到这里考编程,故根据对应考点简要整理。
对低通滤波器来说,H(u,v)应该对高频成分有衰减作用而又不影响低频分量。通常使用低通滤波器实现图像平滑:
理想低通滤波器过滤了高频成分,高频成分的滤除使图像变模糊,但过滤后的图像往往含有“抖动”或“振铃”现象。所谓“振铃”,就是指输出图像的灰度剧烈变化处产生的震荡,就好像钟被敲击后产生的空气震荡。
与理想低通滤波器相比,经ButterWorth低通滤波器处理的图像模糊程度会大大减少,并且过滤后的图像没有“抖动”或“振铃”现象。
指数低通滤波器的平滑效果与ButterWorth低通滤波器大致相同。
高通频域滤波是加强高频成分的方法,它使高频成分相对突出,低频成分相对抑制,从而实现图像锐化。
理想高通滤波器只保留了高频成分。
与理想高通滤波器相比,经ButterWorth高通滤波器处理的图像会更平滑。
指数高通滤波器的锐化效果与ButterWorth高通滤波器大致相同。
(1)使用ButterWorth低通滤波对一幅含噪音的灰度图像进行平滑操作
#include "cvv.hpp"
using namespace cv;
int main() {
Mat X = imread("lena-n.jpg", 0); // 含噪声的灰度图像
if(X.empty())
return -1;
imshow("源图像", X);
filter_dft(X, X, 25, BUTTER_L); // ButterWorth低通滤波
normalize(X, X, 255, 0, NORM_INF); // 增大亮度以便于观察
imshow("结果图像", X);
waitKey();
}
(2)使用ButterWorth高通滤波对一幅灰度图像进行锐化操作
#include "cvv.hpp"
using namespace cv;
int main() {
Mat X = imread("lena.jpg", 0); // 灰度图像
if(X.empty())
return -1;
imshow("源图像", X);
filter_dft(X, X, 60, BUTTER_H); // ButterWorth高通滤波
normalize(X, X, 255, 0, NORM_INF); // 增大亮度以便于观察
imshow("高通滤波", X);
waitKey();
}
在对图像进行处理前,对图像整体(当然也可以是局部)的灰度分布情况作一些分析了解,通常是很有好处的。对图像的灰度分布进行分析的重要手段就是建立灰度直方图。
灰度直方图是灰度级的函数,它表示图像中具有某种灰度级的像素的个数,反映了图像中某种灰度出现的频率。也就是说,灰度直方图是对图像的所有像素的灰度分布按灰度值的大小显示灰度值出现频度的统计图。
通常,灰度直方图的横轴用来表示灰度值,纵轴用来表示频度。频度是具有某一灰度值(或属于某一子区域的灰度值)的像素在图像中出现的次数。
假设有一幅4×4的8灰度级图像,图像数据及其灰度直方图分别如左图和右图所示:
根据图像数据,灰度值为0, 1, 2, 3, 4, 5, 6, 7的像素的频度分别是1, 2, 6, 2, 3, 1, 0, 1,因此在灰度刻度的0~7处分别作一条以该灰度值对应的频度值为长度的直线即可完成该图像的灰度直方图。
假设有一个矩阵包含一张图像的灰度值(如左图所示):
灰度值的范围包含256个值,可以将这个范围均匀分割成若干子区域,如8个均匀子区域,即[0,256)=[0,32)∪[32,64)∪...∪[224,256)。
将灰度值范围均匀分割成若干子区域以后,统计灰度值属于每一个子区域的像素数目。
采用这一方法来统计上面的数字矩阵,可以得到如右图所示的直方图(x轴表示子区域,y轴表示属于各个子区域的像素个数)。
// 计算一个单通道图像的直方图(源图像, 直方图, 大小, 范围)
void MyCalcHist(Mat image, Mat &hist, int size, vector range) {
float a = range[0], b = range[1]; // 下界, 上界
if(b < a)
swap(a, b);
Mat1f H(1, size, 0.0); // 直方图初始值为0
for(auto v : Mat1f(image)) {
int i = (v - a) * size / (b - a); // 当前像素所在子区域
++H(i); // 相应子区域的像素数目增加1
}
hist = H; // 记录结果
}
此部分为老师提到的编程题可能涉及的基础部分知识,定位为教材第2、3、11、12章,具体掌握情况以大致可以完成课程实验为标准即可,故在此进行大致整理,所涉及的知识点不一定覆盖所有实际所需内容,因此具体复习参考教材和课程实验,以及涉及编程题考点的示例代码即可。
一组功能相同或相近的函数的函数名使用不同的后缀以支持不同的数据类型和格式,如glEvalCoord2f()、glEvalCoord2d()和glEvalCoord2dv()等,其中2表示有2个参数,f、d分别表示参数的类型是float和double,v表示参数以向量形式出现。
OpenGL定义了一些特殊的类型名,如GLint和GLfloat。其实就是32位C语言中的float和int等类型。在
// Frame.c
#include
void init() {
/* 全局初始化。主要用于设置一些全局的状态,如颜色模式、
窗口的初始位置和大小等。使用默认值时不需要定义该函数。
*/
}
void init2() {
/* 当前窗口初始化。主要用于设置一些与当前窗口关联的状态或开关,
如光照处理、光源特性、深度检测和裁剪等。
使用默认值时不需要定义该函数。
*/
}
void Reshape(int w, int h) {
/* 设置投影方式和观察体。主要使用glViewport()、glOrtho()、glFrustum()、
gluPerspective()和gluOrtho2D()等。
使用默认值时不需要定义该函数。
*/
}
void Paint() {
/* 使用OpenGL库函数构造对象的数学描述,包括点线面的位置、
几何变换和光照处理等,是OpenGL的主要部分。
*/
}
int main(int argc, char *argv[]) {
glutInit(&argc, argv); // 初始化GLUT, 记录main()的参数
init(); // 全局初始化, 使用默认值时不是必需的
glutCreateWindow("窗口标题"); // 创建程序窗口,指定窗口标题
init2(); // 当前窗口初始化, 使用默认值时不是必需的
// 注册回调函数
glutDisplayFunc(Paint); // 指定场景绘制函数,必需
glutReshapeFunc(Reshape); // 指定窗口变化回调函数,缺省则使用默认值
glutMainLoop(); // 开始循环执行OpenGL命令
}
① glFlush()
② glFinish()
【函数原型】void glBegin(GLenum mode);
【功能】表示一个基本图元定义的开始。
【参数】mode可选下列符号常量。
【函数原型】void glEnd(void);
【功能】表示一个基本图元定义的结束。
※ 预定义的几何形体详见教材。
#include
void Viewport(int x, int y, int w, int h) {
glViewport(x, y, w, h); // 定义视口
glLoadIdentity(); // 消除其他视口的影响, 函数介绍见后续章节
}
void Paint(){
int w = glutGet(GLUT_WINDOW_WIDTH) / 2; // 计算视区宽度
int h = glutGet(GLUT_WINDOW_HEIGHT) / 2; // 计算视区高度
glClearColor(1, 1, 1, 1); // 白色背景
glClear(GL_COLOR_BUFFER_BIT); // 清除颜色缓存
Viewport(0, 0, w, h); // 左下方视口
glColor3f(1, 0.8, 0.6); // 设置当前颜色, 茶色
glRectf(-0.8, -0.8, 0.8, 0.8); // 定义正方形
Viewport(w, 0, w, h); // 右下方视口
glColor3f(0, 1, 0); // 设置当前颜色, 绿色
glutSolidTeapot(0.6); // 定义犹他茶壶
Viewport(0, h, w, h); // 左上方视口
glColor3f(0, 0, 1); // 设置当前颜色, 蓝色
glRotatef(45, 1, 1, 0); // 调整立方体方向, 函数介绍见后续章节
glutWireCube(1); // 线框立方体, 边长为1
Viewport(w, h, w, h); // 右上方视口
glColor3f(1, 0, 1); // 设置当前颜色, 紫色
glRotatef(-90, 1, 0, 0); // 调整两极方向, 函数介绍见后续章节
glutWireSphere(0.8, 24, 12); // 线框球体, 半径, 经线数, 纬线数
glFlush(); // 强制OpenGL命令序列在有限的时间内完成执行
}
int main(int argc, char *argv[]) {
glutInit(&argc, argv); // 初始化GLUT, 记录main()的参数
glutCreateWindow("四个预定义几何形体"); // 指定窗口标题
glutDisplayFunc(Paint); // 指定场景绘制函数
glutMainLoop(); // 开始执行
}
使用()运算。
※ 代码示例
// 在源图像中选取一个矩形子集,并将该矩形子集乘以0.75,然后显示图像
#include
using namespace cv;
int main() {
Mat im = imread("lena.jpg"); // 载入彩色图像
if(im.empty())
return -1; // 载入失败
Mat roi = im({ 125, 125, 100, 50 }); // 选取矩形子集
roi *= 0.75; // 降低选取区域亮度
imshow("SubMat", im); // 显示图像
waitKey();
}