图像的几何变换
昆明理工大学(数字图像处理)实验报告 实验名称: 图像的几何变换 专 业: 电子信息科学与技术 姓 名: 学 号: 成 绩:
[实验目的]
1、学习几种常见的图像几何变换,并通过实验体会几何变换的效果。
2、掌握图像平移、剪切、缩放、旋转、镜像、错切等几何变换的算法原理及编程实现。
[实验内容]
1、图像的平移。
2、图像的镜像变换。
3、图像的缩放。
4、图像的旋转。
[实验原理]
1、图像的平移
图像平移 ( translation)是将图像中所有的点都按照指定的平移量水平、垂直移动。
如下图所示,初始坐标为(x0,y0)的点经过平移(tx,ty)(以向右,向下为正方向) 后,坐标变为(x1,y1)。这两点之间的关系是x1=x0+tx ,y1=y0+ty。
以矩阵的形式表示为
它的逆变换为:
2、图像的镜像变换
图像的镜像变换分为两种:一种是水平镜像, 另一种是垂直镜像。图像的水平镜像操作是以原图像的垂直中轴线为中心, 将图像分为左右两部分进行对称变换; 图像的垂直镜像操作是以原图像的水平中轴线为中心, 将图像分为上下两部分进行对称变换。镜像变换后图的高和宽都不变。设图像高度为 Height ,宽度为 Width ,原图中的 (x0,y0) 经过水平镜像后坐标将变成 (Width-x0,y0) , 即: x1= Width-x0 ,y1=y0 同样,(x0,y0) 经过垂直镜像后坐标将变成为 (x0,Height-y0) , 即:x1=x0,y1=Height-y0 。
用矩阵表示如下:
水平镜象的变化矩阵为:
垂直镜象的变化矩阵为:
3、图像的缩放
1、 最邻近插值(近邻取样法)
最邻近插值是一种简单的插值算法,也称为零阶插值。它输出的像素灰度值就等于距离它映射到的位置最近的输入像素的灰度值。对于通过反向变换得到的的一个浮点坐标,对其进行简单的取整,得到一个整数型坐标,这个整数型坐标对应的像素值就是目的像素的像素值,也就是说,取浮点坐标最邻近的左上角点(对于DIB 是右上角,因为它的扫描行是逆序存储的)对应的像素值。可见,最邻近插值简单且直观,但得到的图像质量不高;当图像中包含像素之间灰度级有变化的细微结构时,最邻近查值法会在图像中产生人为的加工痕迹。
2、双线性插值
对于一个目的像素,设置坐标通过反向变换得到的浮点坐标为(i+u,j+v),其中i 、j 均为非负整数,u 、v 为[0,1)区间的浮点数,则这个像素得值 f(i+u,j+v) 可由原图像中坐标为 (i,j)、(i+1,j)、(i,j+1)、(i+1,j+1)所对应的周围四个像素的值决定,即:
f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1) 其中f(i,j)表示源图像(i,j)处的的像素值,以
此类推。这就是双线性内插值法。双线性内插值法计算量大,但缩放后图像质量高,不会出现像素值不连续的的情况。由于双线性插值具有低通滤波器的性质,使高频分量受损,所以可能会使图像轮廓在一定程度上变得模糊。
4、图像的旋转
图像的旋转必须指明图像绕着什么旋转。一般图像的旋转是以图像的中心为原点, 旋转一定的角度。旋转后, 图像的大小一般会改变。和图像平移一样, 既可以把转出显示区域 的图像截去, 也可以扩大图像范围以显示所有的图像。举个例子,如图1旋转30度(顺时针方向) 后如右图所示:
图1 旋转前的图
图2旋转后的图
可以看出,旋转后图象变大了。另一种做法是不让图象变大,转出的部分被裁剪掉。如下图,我们采用第一种做法,首先给出变换矩阵。在我们熟悉的坐标系中,将一个点顺时针旋转a 角后的坐标变换公式,如图4所示,r 为该点到原点的距离,在旋转过程中,r 保持不变;b 为r 与x 轴之间的夹角。
图3 旋转后保持原图大小,转出
图4 旋转示意图 的部分被裁掉
旋转前:x0=rcosb;y0=rsinb
旋转a 角度后:
x1=rcos(b-a)=rcosbcosa+rsinbsina=x0cosa+y0sina;
y1=rsin(b-a)=rsinbcosa-rcosbsina=-x0sina+y0cosa; 以矩阵的形式表示:
[实验步骤]
1、图像的平移。
打开菜单编辑器,在主菜单中添加一菜单项,选中弹出式选项,修改菜单名称为“几何运算”。然后建立一下级菜单, 给菜单一个ID 号,修改caption 为“图像的平移”,打开类向导,建立消息响应函数,实现图像灰度线性变换。添加一个线性变换对话框用于输入。调出资源视图窗口,添加ID 为IDD_MOVETRAN的对话框资源,设计如图:
创建对话框类CDialogdl 并按下表关联对应变量:
void CDLView::OnPingyi()
{
// TODO: Add your command handler code here
long w,h;
long i,j;
if(m_DibHead==NULL)
{
MessageBox("请打开一幅图像");
return;
}
w=m_DibHead->biWidth;
h=m_DibHead->biHeight;
int a=h/4,b=w/4;
unsigned char *f=new unsigned char[w*h];
memset(f,0,w*h);
for(i=a;i
{
for(j=b;j
{
f[i*w+j]=m_Image[(i-a)*w+(j-b)];
}
}
memcpy(m_Image,f,w*h);
Invalidate();
}
2、图像的镜像变换。
void CDLView::OnShuipjx() //水平
{
// TODO: Add your command handler code here
long w,h;
long i,j;
w=m_DibHead->biWidth;
h=m_DibHead->biHeight;
unsigned char*lpdst=new unsigned char[w*h];
for(i=0;i
for(j=0;j
{
lpdst[i*w+w-j-1]=m_Image[i*w+j];
}
memcpy(m_Image,lpdst,w*h);
Invalidate();
delete[]lpdst;
}
void CDLView::OnChuizjx() //垂直
{
long w,h;
long i,j;
w=m_DibHead->biWidth;
h=m_DibHead->biHeight;
unsigned char*lpdst=new unsigned char[w*h];
for(i=0;i
for(j=0;j
{
lpdst[(h-1-i)*w+j]=m_Image[i*w+j];
}
memcpy(m_Image,lpdst,w*h);
Invalidate();
delete[]lpdst;
}
3、图像的缩放。
建立消息响应函数,实现图像灰度线性变换。添加一个线性变换对话框用于输入。调出资源视图窗口,在toolbar 下添加ID 为ID_FD和ID_SX的按钮资源,设计如图:
void CDLView::OnFangd() //放大
{
// TODO: Add your command handler code here
CSize Dibsize = GetDibSize();
if ((Dibsize.cx * m_x * 1.5)
{
if ((Dibsize.cy * m_x * 1.5)
{
m_x = (int)(m_x * 1.5);
Invalidate();
}
}
}
void CDLView::OnSuox() //缩小
{
// TODO: Add your command handler code here
if (m_x > 2)
{
m_x = (int)(m_x / 1.5);
Invalidate();
}
}
4、图像的旋转。
void CDLView::OnXuanzhuan()
{
// TODO: Add your command handler code here if(m_DibHead==NULL)
{
MessageBox("请打开一幅图像");
return;
}
m_DibHead->biWidth=(m_DibHead->biWidth+3)/4*4; long i,j;
long w,h;
w=m_DibHead->biWidth;
h=m_DibHead->biHeight;
unsigned char *m_pImgDataOut=new unsigned char[w*h]; memset(m_pImgDataOut,0,w*h);
for(i=0;i
{
for(j=0;j
{
m_pImgDataOut[i*w+j]=m_Image[j*w+(w-i-1)]; }
}
memcpy(m_Image,m_pImgDataOut,w*h);
delete []m_pImgDataOut;
Invalidate();
}
[实验结果]
1、图像的平移。
变换前
2、图像的镜像变换。 水平镜像:
变换前
垂直镜像:
变换前
3、图像的缩放。
放大: 变换后 变换后 变换后
变换前
变换后 缩小:
变换前
变换后
4、图像的旋转。
变换前 变换后
[实验总结]
图像的几何变换不改变图像的像素值,而是改变像素所在
的几何位置。