【python】图像映射:单应性变换与图像扭曲
【python】圖像映射:單應(yīng)性變換與圖像扭曲
- 單應(yīng)性變換(Homography)
- 圖像扭曲(仿射變換)
- 圖中圖
- 分段仿射扭曲
單應(yīng)性變換(Homography)
單應(yīng)性變換(Homography)即一個(gè)平面中的點(diǎn)到另一個(gè)平面的映射關(guān)系,如下圖所示,使用單應(yīng)性矩陣,將不同角度拍攝的圖像圖1和圖2變換到同一平面。
而實(shí)現(xiàn)單應(yīng)性變化的重點(diǎn)就是對(duì)單應(yīng)性矩陣H的求解。如下圖所示,其中x1y1表示圖像一的矩陣數(shù)據(jù),x2y2表示圖像二的矩陣數(shù)據(jù),而H則為單應(yīng)性矩陣,通過(guò)求解H即可得出兩圖像間的映射關(guān)系。
在一般情況下,矩陣A不可逆,若需要求得t的值(下圖中t即為單應(yīng)性矩陣)則需要做一定的數(shù)學(xué)變換
如下公式所示,進(jìn)行轉(zhuǎn)換后,通過(guò)計(jì)算最小二乘解求得最小特征值對(duì)應(yīng)的特征向量
再通過(guò)DLT(Direct Linear Transform)算法解決該最小二乘問(wèn)題,如下圖,通過(guò)DTL算法得A = UDVt, 而h (單應(yīng)性矩陣)即為V的最后一行
單應(yīng)性變換的結(jié)果誒下圖,圖中將圖1與圖2通過(guò)單應(yīng)性變換進(jìn)行了圖片融合
圖像扭曲(仿射變換)
圖像扭曲即仿射變換。仿射變換變化包括縮放、平移、旋轉(zhuǎn)、反射等,,原來(lái)的直線仿射變換后還是直線,原來(lái)的平行線經(jīng)過(guò)仿射變換之后還是平行線。
仿射變換中一些性質(zhì)會(huì)保持不變:
1.凸性
2.共線性:若幾個(gè)點(diǎn)變換前在一條線上,則仿射變換后仍然在一條線上
3.平行性:若兩條線變換前平行,則變換后仍然平行
4.共線比例不變性:變換前一條線上兩條線段的比例,在變換后比例不變
from numpy import *
from matplotlib.pyplot import *
from scipy import ndimage
from PIL import Imageim = array(Image.open('11.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()
圖中圖
如下圖所示,將一圖融入了二圖中,雖然圖片有些扭曲但這就是該算法所需要呈現(xiàn)的效果。圖像中的圖像即為仿射扭曲的一個(gè)簡(jiǎn)單例子,它將圖像或者圖像的一部分放置在另一幅圖像中,使得他們能夠和指定的區(qū)域或者標(biāo)記物對(duì)齊。為了能夠?qū)崿F(xiàn)更加精準(zhǔn)的匹配,我們可以使用分段仿射扭曲。
from numpy import *
from matplotlib.pyplot import *
from scipy import ndimage
from PIL import Image
def Haffine_from_points(fp, tp):"""計(jì)算H仿射變換,使得tp是fp經(jīng)過(guò)仿射變換H得到的"""if fp.shape != tp.shape:raise RuntimeError('number of points do not match')# 對(duì)點(diǎn)進(jìn)行歸一化(對(duì)數(shù)值計(jì)算很重要)# --- 映射起始點(diǎn) ---m = mean(fp[:2], axis=1)maxstd = max(std(fp[:2], axis=1)) + 1e-9C1 = diag([1/maxstd, 1/maxstd, 1]) C1[0][2] = -m[0]/maxstdC1[1][2] = -m[1]/maxstdfp_cond = dot(C1,fp)# --- 映射對(duì)應(yīng)點(diǎn) ---m = mean(tp[:2], axis=1)C2 = C1.copy() # 兩個(gè)點(diǎn)集,必須都進(jìn)行相同的縮放C2[0][2] = -m[0]/maxstdC2[1][2] = -m[1]/maxstdtp_cond = dot(C2,tp)# 因?yàn)闅w一化后點(diǎn)的均值為0,所以平移量為0A = 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所示,# 創(chuàng)建矩陣B和Ctmp = V[:2].TB = 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]def image_in_image(im1, im2, tp):"""使用仿射變換將im1放置在im2上,使im1圖像的角和tp盡可能的靠近tp是齊次表示的,并且是按照從左上角逆時(shí)針計(jì)算的"""# 扭曲的點(diǎn)m,n = im1.shape[:2]fp = array([[0,m,m,0],[0,0,n,n],[1,1,1,1]])# 計(jì)算仿射變換,并且將其應(yīng)用于圖像im1中H = Haffine_from_points(tp,fp)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_tim1 = array(Image.open('31.jpg').convert('L'))
im2 = array(Image.open('32.jpg').convert('L'))gray()
subplot(131)
imshow(im1)
axis('equal')
axis('off')
subplot(132)
imshow(im2)
axis('equal')
axis('off')# 選定一些目標(biāo)點(diǎn)
tp = array([[264, 538, 540, 264], [40, 36, 605, 605], [1, 1, 1, 1]])im3 = image_in_image(im1, im2, tp)
subplot(133)
imshow(im3)
axis('equal')
axis('off')
show()
分段仿射扭曲
為了能夠?qū)崿F(xiàn)圖像中角點(diǎn)的精確匹配,我們通常使用分段仿射扭曲。即首先通過(guò)三角化圖像塊再使用仿射扭曲來(lái)扭曲每個(gè)三角形,其中的核心部分即為圖像塊的三角化,可以通過(guò)狄洛克三角剖分實(shí)現(xiàn),其具體如下:
from PIL import Image
from pylab import *
import numpy as np
from scipy.spatial import Delaunayx,y = array(np.random.standard_normal((2,100)))
"""centers, edges, tri, neighbors = md.delaunay(x, y"""
tri = Delaunay(np.c_[x,y]).simplicesfigure()for t in tri:t_ext = [t[0],t[1],t[2],t[0]]plot(x[t_ext], y[t_ext], 'g')plot(x,y,'*')
axis('off')
show()
總結(jié)
以上是生活随笔為你收集整理的【python】图像映射:单应性变换与图像扭曲的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【Python】函数图像绘制:二维图像、
- 下一篇: 2021 年第十一届 MathorCup