图像几何变换之仿射变换原理及实现 | 您所在的位置:网站首页 › 二维图像 › 图像几何变换之仿射变换原理及实现 |
今天学习了仿射变换,将一张图片放置到另一张图片,感觉十分有趣,所以写了这篇博客,与大家一起分享一下! 一、仿射变换 1.什么是仿射变换 2.alpha通道 3.仿射变换的求解 二、仿射变换的实现 1.主函数 2.主要函数的介绍 一、仿射变换 1.什么是仿射变换(1)放射变换的定义 仿射变换是将一个平面的点映射到另一个平面内的二维投影。仿射变换保持了二维图形的“平直性”,即原来是直线的地方还是直线。仿射变换具有很强的实用性,比如图像配准、图像纠正和纹理纠正,以及创建全景图像等。仿射变换的效果如下图所示: (2)仿射变换的数学表示 仿射变换是一种二维坐标(x, y)到二维坐标(u, v)的线性变换,其数学表达式形式如下: 对应的齐次坐标矩阵表示形式为: 其中,取 坐标变换: 实现将一张图片放置到另一张图片上去,其实就是已知 (3)仿射变换的几何意义 仿射变换可以理解成一系列的原子变换复合实现的,具体暴扣:平移、旋转、尺度变换等。 a.平移 数学形式: 矩阵形式: 平移变换包含两个未知量,即 b.旋转 矩阵形式:
c.尺度变换 矩阵形式: d.刚体运动:旋转平移缩放 矩阵形式: alpha用来衡量一个像素或图像的透明度。在非压缩的32位RGB图像中,每个像素是由四个部分组成:一个alpha通道和三个颜色分量(R、G和B)。当Alpha值为0时,该像素是完全透明的,而当Alpha值为255时,则该像素是完全不透明。 alpha用于图像m1经过仿射变换后,将图像m1放置到图像m2时,只有alpha大于0的区域才能放置到图像m2上,alpha为0的区域在融合的时候就变成透明了。 3.仿射变换的求解(1)流程 a.输入两张图像m1和m2 b.设置所需要放置的区域矩阵tp c.获取m1的宽m和高n,并设置原图区域矩阵为fp d.根据fp和tp计算仿射变换参数矩阵H e.将m1放置到m2上去 (2)仿射变换参数矩阵H的求解 放射变换求解的关键就是H的求解,我们已知原图区域矩阵fp和需要放置的tp,需要求得仿射变换参数矩阵H。 我们利用最小二乘法求解H,其基本步骤如下: a.检查tp和fp大小是否一致,若不一致则报错 b.对fp进行归一化 c.对tp进行归一化 d.利用SVD进行奇异值分解,剔除异常值,求得H 二、仿射变换的实现 1.主函数: # -*- coding: utf-8 -*- from PCV.geometry import warp, homography from PIL import Image from pylab import * from scipy import ndimage # im1仿射到im2的例子 #打开两张图片 im1 = array(Image.open('D:/test/beatles.jpg').convert('L')) im2 = array(Image.open('D:/test/billboard_for_rent.jpg').convert('L')) # 选定一些目标点,数组tp表示目标区域,三行分别代表y、x和齐次,其中区域按从左上角逆时针旋转, tp = array([[120,260,260,120],[16,16,305,305],[1,1,1,1]])#将一些目标点存储到数组中 im3 = warp.image_in_image(im1,im2,tp) #使用仿射变换将m1放置到m2 figure() gray() subplot(141) axis('off') imshow(im1) subplot(132) axis('off') imshow(im2) subplot(133) axis('off') imshow(im3) show() 2.主要函数的介绍:(1)wrap.image_in_image(im1,im2,tp) 函数的意义是通过方式变换将图像m1放置到图像m2的指定区域tp中 def image_in_image(im1,im2,tp): """使用仿射变换将m1放置到m2,使得m1图像的角和tp尽可能的靠近。 tp是齐次表示的,并且按照从左上角逆时针计算的""" # 扭曲的点 m,n = im1.shape[:2]#获取m1的高m宽n fp = array([[0,m,m,0],[0,0,n,n],[1,1,1,1]]) #计算仿射变换,并且将其应用于图像im1 H = homography.Haffine_from_points(tp,fp)#返回给定点对的最优仿射变换求H im1_t = ndimage.affine_transform(im1,H[:2,:2], (H[0,2],H[1,2]),im2.shape[:2])#图像扭曲 alpha = (im1_t > 0) return (1-alpha)*im2 + alpha*im1_t(2)homography.Haffine_from_points(tp,fp) 函数的意义是通过原图像矩阵fp和仿射变换后的图像矩阵tp求得H def Haffine_from_points(fp,tp): """计算H,仿射变换,使得tp是fp经过仿射变换H得到的""" if fp.shape != tp.shape: raise RuntimeError('number of points do not match') # 对点进行归一化 # 映射起始点 m = mean(fp[:2], axis=1)#取fp的前两行,压缩列求平均值 maxstd = max(std(fp[:2], axis=1)) + 1e-9 #取fp的前两行,压缩列求标准差,取最大值 C1 = diag([1/maxstd, 1/maxstd, 1]) C1[0][2] = -m[0]/maxstd C1[1][2] = -m[1]/maxstd fp_cond = dot(C1,fp) # 映射对应点 m = mean(tp[:2], axis=1) C2 = C1.copy() #两个点集,必须都进行相同的缩放 C2[0][2] = -m[0]/maxstd C2[1][2] = -m[1]/maxstd tp_cond = dot(C2,tp) #因为归一化后点的均值为0,因此平移为0 A = concatenate((fp_cond[:2],tp_cond[:2]), axis=0)#数组拼接 U,S,V = linalg.svd(A.T)#奇异值分解,用小的多的数据集来表示原始数据集 #创建B和C矩阵 tmp = V[:2].T B = tmp[:2] C = tmp[2:4] #B的伪逆矩阵和C逐元素相乘,与zero(2,1)拼接 tmp2 = concatenate((dot(C,linalg.pinv(B)),zeros((2,1))), axis=1) H = vstack((tmp2,[0,0,1]))#数组合并 # 反归一化 H = dot(linalg.inv(C2),dot(H,C1)) return H / H[2,2]效果如下图所示: 左边为图像m1,中间为图像m2,右边为仿射变换后的效果图。我们可以清楚的看到m1放到了m2的指定区域,实现了两张图片的融合。 |
CopyRight 2018-2019 实验室设备网 版权所有 |