概述
文章目录
- 一、单应性变换
- 直接线性变换
- 仿射变换
- 二、图像扭曲
- 图像中的图像
- 使用三角形仿射扭曲效果
一、单应性变换
单应性变换时将一个平面内的点映射到另一个平面内的二维码投影变换。本质上,单应性变换H,按照下面的方程映射二维中的点:
或者
单应性矩阵H仅以来尺度定义,所以它有8个独立的自由度。通常使用w=1来归一化点,使点具有唯一的图像坐标x和y。这个额外的坐标使得我们可以简单地使用一个矩阵来表示变换。
直接线性变换
单应性矩阵可以由两幅图像(或者平面)中对对应对计算出来。已知一个完全射影变换具有8个自由度。根据对应点约束,每个对应点对可以写出两个方程,分别对应于x和y坐标。因此,计算单应性矩阵H需要4个对应点对。
DLT,直线线性变换使给定4个或者横夺对应点对矩阵,来计算单应性矩阵H的算法。将单应性矩阵作用在对应点对上,重新写出改方程,可以得到下面的方程:
或者Ah=0,其中A是一个具有对应点对二倍数量行数的矩阵。将这些对应点对方程的系数堆叠到一个矩阵中,我们可以使用SVD算法找到H的最小二乘解。
def H_from_points(fp, tp):
"""使用线性DLT方法,计算单应性矩阵H,使fp映射到tp。点自动进行归一化"""
if fp.shape != tp.shape:
raise RuntimeError('number of points do not match')
# 对点进行归一化(对数值计算很重要)
# --- 映射起始点 ---
m = mean(fp[:2], axis=1)
maxstd = max(std(fp[:2], axis=1)) + 1e-9
C1 = diag([1 / maxstd, 1 / maxstd, 1])
C1[0][2] = -m[0] / maxstd
C1[1][2] = -m[1] / maxstd
fp = dot(C1, fp)
# --- 映射对应点 ---
m = mean(tp[:2], axis=1)
maxstd = max(std(tp[:2], axis=1)) + 1e-9
C2 = diag([1 / maxstd, 1 / maxstd, 1])
C2[0][2] = -m[0] / maxstd
C2[1][2] = -m[1] / maxstd
tp = dot(C2, tp)
# 创建用于线性方法的矩阵,对于每个对应对,在矩阵中会出现两行数值
nbr_correspondences = fp.shape[1]
A = zeros((2 * nbr_correspondences, 9))
for i in range(nbr_correspondences):
A[2 * i] = [-fp[0][i], -fp[1][i], -1, 0, 0, 0,
tp[0][i] * fp[0][i], tp[0][i] * fp[1][i], tp[0][i]]
A[2 * i + 1] = [0, 0, 0, -fp[0][i], -fp[1][i], -1,
tp[1][i] * fp[0][i], tp[1][i] * fp[1][i], tp[1][i]]
U, S, V = linalg.svd(A)
H = V[8].reshape((3, 3))
# 反归一化
H = dot(linalg.inv(C2), dot(H, C1))
# 归一化,然后返回
return H / H[2, 2]
仿射变换
由于仿射变换有6个自由度,因此我们需要三个对应点对来估计矩阵H。通过将最后两个元素设置为0,仿射变换可以用上面的DLT算法估计得出。
下面是计算仿射矩阵H的方法。其中tp是变换后的坐标,fp是变换前的坐标,通过计算H,使得tp是fp通过仿射变换矩阵H得到的,然后返回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)
maxstd = max(std(fp[:2], axis=1)) + 1e-9
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)
# 如Hartley和Zisserman著的Multiplr View Geometry In Computer,Scond Edition所示,
# 创建矩阵B和C
tmp = V[:2].T
B = tmp[:2]
C = tmp[2:4]
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]
二、图像扭曲
对图像块应用仿射变换,我们将其称为图像扭曲。
from array import array
from numpy import *
from matplotlib.pyplot import *
from scipy import ndimage
from PIL import Image
im = array(Image.open('image1.jpg').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]))
gray()
subplot(121)
imshow(im)
axis('off')
subplot(122)
imshow(im2)
axis('off')
show()
输出图像结果中丢失的像素用0来填充。
图像中的图像
仿射扭曲的一个简单的例子是,将图像或者图像的一部分放置在另一幅图像中,使得它们能够和指定的区域或者标记物对齐。
from numpy import *
from matplotlib.pyplot import *
from numpy import array
from scipy import ndimage
from PIL import Image
import warp
im1 = array(Image.open('cup.jpg').convert('L'))
im2 = array(Image.open('image1.jpg').convert('L'))
gray()
subplot(131)
imshow(im1)
axis('equal')
axis('off')
subplot(132)
imshow(im2)
axis('equal')
axis('off')
# 4个点的y,x坐标
tp = array([[500, 680, 680, 500], [80, 80, 200, 200], [1, 1, 1, 1]])
im3 = warp.image_in_image(im1, im2, tp)
subplot(133)
imshow(im3)
axis('equal')
axis('off')
show()
测试将杯子放到桌子上
通过选定的四个点来确定杯子图片在桌子图片中的坐标,在调整时可以通过输出坐标系来确定大概的坐标范围。
使用三角形仿射扭曲效果
对于三个点,仿射变换可以将一幅图像进行扭曲,使这三对对应点可以完美地匹配上。这是因为仿射变换有6个自由度,三个对应点对可以给出6个约束条件。所以我们也可以尝试将图像分成两个三角形,然后对他们分别进行图像扭曲操作。
from array import array
from numpy import *
from matplotlib.pyplot import *
from scipy import ndimage
from PIL import Image
import warp
import homography
im1 = array(Image.open('McDonald.jpg').convert('L'))
im2 = array(Image.open('advertise.jpg').convert('L'))
# 选定im1角上的一些点
print(im1.shape)
m, n = im1.shape[:2]
# 麦当劳的4个顶点坐标
fp = array([[0, m, m, 0], [0, 0, n, n], [1, 1, 1, 1]])
# 广告牌的坐标
tp = array([[135, 305, 345, 175], [75, 70, 470, 460], [1, 1, 1, 1]])
# 第一个三角形
tp2 = tp[:, :3] # 前三个点
fp2 = fp[:, :3]
# 计算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
alpha = warp.alpha_for_triangle(tp2, im2.shape[0], im2.shape[1])
im3 = (1 - alpha) * im2 + alpha * im1_t
# 第二个三角形
tp2 = tp[:, [0, 2, 3]] # 第1、3、4个坐标
fp2 = fp[:, [0, 2, 3]]
# 计算H
H = homography.Haffine_from_points(tp2, fp2)
im1_t = ndimage.affine_transform(im1, H[:2, :2],
(H[0, 2], H[0, 2]), im2.shape[:2])
# 三角形的alpha图像
alpha = warp.alpha_for_triangle(tp2, im2.shape[0], im2.shape[1])
im4 = (1 - alpha) * im3 + alpha * im1_t
figure()
gray()
imshow(im4)
axis("equal")
axis("off")
show()
下面要讲麦当劳的图片放到广告牌上
对于整幅图像,使用放射扭曲效果没有使用三角形仿射变换的好。简单为每个三角形创建alpha图像,然后将所有的图像合并起来。该三角形的alpha图像可以简单地通过检查像素的坐标是否能够写成三角形顶点坐标的凸组合来计算得出。通过将图片分成两个三角形来仿射扭曲成功将图片帖满广告牌。
最后
以上就是单薄镜子为你收集整理的计算机视觉第三章 图像到图像的映射一、单应性变换二、图像扭曲的全部内容,希望文章能够帮你解决计算机视觉第三章 图像到图像的映射一、单应性变换二、图像扭曲所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复