仿射变换
在学习计算机视觉这门课程的时候,我们会接触到关于图像与图像之间的映射问题,图像映射可以应用于很多领域,例如我们最近玩的很火的换脸游戏,和手机相机中的全景拍摄功能,都有应用到图像应用的知识。
初学图像到图像的映射,在仿射变换前会首先介绍单应性变换。
单应性变换
单应性变换是指将一个平面内的点映射到另一个平面内的二维投影变换。平面是指图像或者是三维空间中的平面表面。单应性变换具有很强的实用性。本质上,单应性变换 H ,按照下面方程映射二维中的点。(齐次坐标意义下)
或
x ’ = H x
单应星矩阵具有8个独立的自由度。所以通常用w=1来归一化点,这样一来,点具有唯一的图像坐标x和y。这个坐标可以使我们简单地使用一个矩阵来表示变换。
仿射变换
图像变换有很多种,例如一个最简单的变换——二维刚体变换,即对图像进行旋转或者平移。t=[tx,ty]可以表示平移向量。
而我们今天学习的仿射变换,是指二维坐标到二维坐标的线性变换。保持图像的“平直性”和“平行性”。但是角度可能会发生变换。任意一个仿射变换都可以表示为乘以一个矩阵(线性变换)再加上一个平移向量(平移)的形式。
该图像引用于单应性变换、仿射变换、透视变换
仿射变换是两个旋转因子和两个缩放因子的组合。所以它又多了两个自由度,共6个自由度。和相似变换不同,它不具有保角性和保持距离比的性质。尽管如此,它仍具有“保持平行”的特性,即原图的平行线,变换后仍是平行线。[^1]
A可被分解如下:
其中R(θ)、R(ϕ)是旋转矩阵,D是对角矩阵:
其中,λ 1 ,λ 2 可被认为是两个方向的缩放比例值。
以上三个公式原理引用于图像单应性变换理解
α通道(Alpha通道)
在图形图像学中,透明通道也称,表示数字图像中像素点的透明度。我们通常知道的RGB图像,其实还有一种RGBA图像,就是在RGB图像中还加入了透明度的概念,当A=0时,表示完全透明。当A=1时,表示不透明。
代码展示
1、然后我们根据代码演示一下仿射变换。看一下简单的仿射变换的作用
from scipy import ndimage
from PIL import Image
from pylab import *
im = array(Image.open('SDL6.png').convert('L'))
H = array([[1.4,0.05,-100],[0.05,1.5,-100],[0,0,1]])
im2 = ndimage.affine_transform(im,H[:2,:2],(H[0,2],H[1,2]))
figure()
gray()
subplot(121)
axis('off')
imshow(im)
subplot(122)
axis('off')
imshow(im2)
show()
结果演示(集美大学尚大楼):
2、将一张图片平移到另一张图片上
# -*- coding: utf-8 -*-
from PCV.geometry import warp, homography
from PIL import Image
from pylab import *
from scipy import ndimage
#tri = Delaunay(np.c_[x,y]).simplices
# example of affine warp of im1 onto im2
im1 = array(Image.open('尚大楼40.jpg').convert('L'))
im2 = array(Image.open('尚大楼41.jpg').convert('L'))
# set to points
tp = array([[120,260,260,120],[16,16,305,305],[1,1,1,1]])
#tp = array([[675,826,826,677],[55,52,281,277],[1,1,1,1]])
im3 = warp.image_in_image(im1,im2,tp)
figure()
gray()
subplot(141)
axis('off')
imshow(im1)
subplot(142)
axis('off')
imshow(im2)
subplot(143)
axis('off')
imshow(im3)
# set from points to corners of im1
m,n = im1.shape[:2]
fp = array([[0,m,m,0],[0,0,n,n],[1,1,1,1]])
# first triangle
tp2 = tp[:,:3]
fp2 = fp[:,:3]
# compute H
H = homography.Haffine_from_points(tp2,fp2)
im1_t = ndimage.affine_transform(im1,H[:2,:2],
(H[0,2],H[1,2]),im2.shape[:2])
# alpha for triangle
alpha = warp.alpha_for_triangle(tp2,im2.shape[0],im2.shape[1])
im3 = (1-alpha)*im2 + alpha*im1_t
# second triangle
tp2 = tp[:,[0,2,3]]
fp2 = fp[:,[0,2,3]]
# compute H
H = homography.Haffine_from_points(tp2,fp2)
im1_t = ndimage.affine_transform(im1,H[:2,:2],
(H[0,2],H[1,2]),im2.shape[:2])
# alpha for triangle
alpha = warp.alpha_for_triangle(tp2,im2.shape[0],im2.shape[1])
im4 = (1-alpha)*im3 + alpha*im1_t
subplot(144)
imshow(im4)
axis('off')
show()
tp = array([[120,260,260,120],[16,16,305,305],[1,1,1,1]])//其中array([1],[2],[3]),[1]表示的是图像2的y坐标,
顺序是从左上角第一个点开始依次逆时针的四个点的y坐标,[2]表示的是图像2的x坐标,顺序是从左上角第一个
点开始依次逆时针的四个点的x坐标,[3]表示的是α通道。
结果截图:
接下来,要将图像1平移到想要的位置,九江鼠标移动到图像上找坐标:
得到坐标
然后改变tp中的坐标
tp = array([[300,500,500,300],[200,200,485,485],[1,1,1,1]])
这样就可以做到,将图片移动到图像2固定的地方。
遇到的错误补充:
在运行第二段代码的时候,会在图示处代码出现错误:
这段代码出现的错误,会出现No module named ‘matplotlib.delaunay’
原因就是,如果你的python安装的Matplotlib库如果是Matplotlib3版本,那么matplotlib.delaunay就已经被删掉了,因为Matplotlib3版本已经不再沿用matplotlib.delaunay。
解决方法:
此时你只需要更改PCV文件夹中,打开warp.py文件
将第一行代码改为:
改为
重新安装pcv,就可以解决这个问题。
另外,如果你的python是3版本,而你的pcv是专门为python2准备的,那么你就要在113行和128行的print函数加上括号
改为
这样改完以后重新安装pcv,基本就可以完美运行第二串代码了。
参考资料
1、【Computer Vision】图像单应性变换/投影/仿射/透视 https://www.cnblogs.com/vincentcheng/p/7191014.html
2、单应性变换、仿射变换、透视变换 https://blog.****.net/qq_29462849/article/details/80728757
3、图像单应性变换理解 https://blog.****.net/czl389/article/details/67689625