当前位置:   article > 正文

[VP] 恢复图像镜面扭曲 - 多视觉几何_skimage.transform.warp

skimage.transform.warp


一、算法原理

在这里插入图片描述
感谢老哥提供的图!

图像中的四条线在现实世界中应该是平行的,或者可以说现实世界中的平行线经过扭曲变换 H 变成了上图那样。

那么我们拿到一张扭曲后的图,首先应该是寻找四个点,这四个点互相构成的四条线在现实世界应该两两平行,如上图所示。

第二步,图像中的四个点确定的四条线,会有两个交点 (我们称为“消失点”) ,由这两个消失点,我们就可以确定一条 “消失线” 。

由两个点求线的公式: l = P 1 × P 2 l=P_{1} \times P_{2} l=P1×P2

由两条线求交点公式: P = l 1 × l 2 P = l_{1} \times l_{2} P=l1×l2

第三步,单应矩阵 H = H A H P H = H_{A} H_{P} H=HAHP,其中 H P H_{P} HP为:

[ 1 0 0 0 1 0 l 1 l 2 l 3 ] [100010l1l2l3]

10l101l200l3
10l101l200l3

其中的 l 1 , l 2 , l 3 l_{1}, l_{2}, l_{3} l1,l2,l3 就是第二步计算出的消失线, H A H_{A} HA可以为任何的仿射变换矩阵。

第四步,知道了 H P H_{P} HP就可以用 Skimage.transform.warp 函数来恢复图像,或者DLT算法恢复

恢复后的图如下:

在这里插入图片描述

二、代码实现

1、确定四个点

import cv2
import sympy
import numpy as np
from PIL import Image
from skimage.transform import *
import matplotlib.pyplot as plt
from scipy.interpolate import  griddata
from mpl_toolkits.mplot3d import Axes3D

#四个点坐标
Pa = np.array([[270], [300], [1]])
Pb = np.array([[454], [230], [1]])
Pc = np.array([[637], [300], [1]])
Pd = np.array([[455], [400], [1]])

#绘制一下这四个点看看
img = cv2.imread('Ex-2.PNG')
plt.plot(270, 300, 'o', color='r')
plt.plot(454, 230, 'o', color='r')
plt.plot(637, 300, 'o', color='r')
plt.plot(455, 400, 'o', color='r')
plt.imshow(img)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

在这里插入图片描述

2、由这四个点确定四条线

# Lines
l_ad = np.cross(Pa.T, Pd.T)
l_ad = l_ad / l_ad[0][2]
print(l_ad)

l_bc = np.cross(Pb.T, Pc.T)
l_bc = l_bc / l_bc[0][2]
print(l_bc)

l_ab = np.cross(Pa.T, Pb.T)
l_ab = l_ab / l_ab[0][2]
print(l_ab)

l_cd = np.cross(Pc.T, Pd.T)
l_cd = l_cd / l_cd[0][2]
print(l_cd)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

[[ 0.00350877 -0.00649123 1. ]]
[[ 0.00678952 -0.01774976 1. ]]
[[-9.44669366e-04 -2.48313090e-03 1.00000000e+00]]
[[-8.45308538e-04 -1.53846154e-03 1.00000000e+00]]

3、由四条线确定两个消失点

P1 = np.cross(l_ad, l_bc)
P1 = P1 / P1[0][2]
print("P1: ", P1)

P2 = np.cross(l_ab, l_cd)
P2 = P2 / P2[0][2]
print("P2: ", P2)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

P1: [[-618.34579439 -180.18691589 1. ]]
P2: [[ 1.46307420e+03 -1.53886926e+02 1.00000000e+00]]

4、由这两个消失点确定消失线

Line = np.cross(P1, P2)
Line = Line / Line[0][2]
Line
  • 1
  • 2
  • 3

array([[-7.33035052e-05, 5.80134750e-03, 1.00000000e+00]])

5、由消失线确定 H P H_{P} HP

Hp = np.matrix([[1, 0, 0], [0, 1, 0], [Line[0][0], Line[0][1], Line[0][2]]])
Hp
  • 1
  • 2

matrix([[ 1.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[ 0.00000000e+00, 1.00000000e+00, 0.00000000e+00],
[-7.33035052e-05, 5.80134750e-03, 1.00000000e+00]])

6、由warp函数和 H P H_{P} HP复原图像

plt.imshow(warp(img, np.linalg.inv(Hp)))
  • 1

在这里插入图片描述

7、用DLT复原图像

def image_rebound(mm,nn,hh):
    W = np.array([[1, nn, nn, 1 ],[1, 1, mm, mm],[ 1, 1, 1, 1]])
    ws = np.dot(hh,W)
    ### scaling
    xx = np.vstack((ws[2,:],ws[2,:],ws[2,:]))
    wsX =  np.round(ws/xx)
    bounds = [np.min(wsX[1,:]), np.max(wsX[1,:]),np.min(wsX[0,:]), np.max(wsX[0,:])]
    return bounds

def make_transform(imm,hh):   
    mm,nn = imm.shape[0],imm.shape[0]
    bounds = image_rebound(mm,nn,hh)
    nrows = bounds[1] - bounds[0]
    ncols = bounds[3] - bounds[2]
    s = max(nn,mm)/max(nrows,ncols)
    scale = np.array([[s, 0, 0],[0, s, 0], [0, 0, 1]])
    trasf = scale@hh
    trasf_prec =  np.linalg.inv(trasf)
    bounds = image_rebound(mm,nn,trasf)
    nrows = (bounds[1] - bounds[0]).astype(np.int)
    ncols = (bounds[3] - bounds[2]).astype(np.int)
    return bounds, nrows, ncols, trasf, trasf_prec

def get_new_image(nrows,ncols,imm,bounds,trasf_prec,nsamples):
    xx  = np.linspace(1, ncols, ncols)
    yy  = np.linspace(1, nrows, nrows)
    [xi,yi] = np.meshgrid(xx,yy) # 生成网格点坐标矩阵。
    a0 = np.reshape(xi, -1,order ='F')+bounds[2]
    a1 = np.reshape(yi,-1, order ='F')+bounds[0]
    a2 = np.ones((ncols*nrows))
    uv = np.vstack((a0.T,a1.T,a2.T)) 
    new_trasf = np.dot(trasf_prec,uv)
    val_normalization = np.vstack((new_trasf[2,:],new_trasf[2,:],new_trasf[2,:]))
   
    ### The new transformation
    newT = new_trasf/val_normalization
    
    ### 
    xi = np.reshape(newT[0,:],(nrows,ncols),order ='F') 
    yi = np.reshape(newT[1,:],(nrows,ncols),order ='F')
    cols = imm.shape[1]
    rows = imm.shape[0]
    xxq  = np.linspace(1, rows, rows).astype(np.int)
    yyq  = np.linspace(1, cols, cols).astype(np.int)
    [x,y] = np.meshgrid(yyq,xxq) 
    x = (x - 1).astype(np.int) #Offset x and y relative to region origin.
    y = (y - 1).astype(np.int) 
        
    ix = np.random.randint(im.shape[1], size=nsamples)
    iy = np.random.randint(im.shape[0], size=nsamples)
    samples = im[iy,ix]
       
    int_im = griddata((iy,ix), samples, (yi,xi))
    
    #Plotting
    fig = plt.figure(figsize=(8, 8))
    columns = 2
    rows = 1
    fig.add_subplot(rows, columns, 1)
    plt.imshow(im)
    fig.add_subplot(rows, columns, 2)
    
    plt.imshow(int_im.astype(np.uint8))
    plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
im = np.array(Image.open('Ex-2.PNG'))
bounds, nrows, ncols,  trasf, trasf_prec = make_transform(im,Hp)
  • 1
  • 2
nn,mm  = im.shape[0],im.shape[0]
if max(nn,mm)>1000:
    kk =6
else: kk =5
nsamples = 10**kk         
get_new_image(nrows,ncols,im,bounds,trasf_prec,nsamples)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在这里插入图片描述

8、确定 H − T l T H^{-T}l^{T} HTlT在无穷远处的一条线上

即确定 H − T l T = [ 0 0 1 ] H^{-T}l^{T}=[001]

001
HTlT=001,此处使用的是sympy的符号系统,以证明任何数字均满足此公式

from sympy import *
  • 1
h1 = sympy.Symbol('h1')
h2 = sympy.Symbol('h2')
h3 = sympy.Symbol('h3')
h4 = sympy.Symbol('h4')
h5 = sympy.Symbol('h5')
h6 = sympy.Symbol('h6')

l1 = sympy.Symbol('l1')
l2 = sympy.Symbol('l2')
l3 = sympy.Symbol('l3')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
HaMatrix = sympy.Matrix([[h1, h2, h3], [h4, h5, h6], [0, 0, 1]])
HpMatrix = sympy.Matrix([[1, 0, 0], [0, 1, 0], [l1, l2, l3]])
HpMatrix
  • 1
  • 2
  • 3

在这里插入图片描述

H = HaMatrix*HpMatrix
H
  • 1
  • 2

在这里插入图片描述

l = Matrix([[l1], [l2], [l3]])
l
  • 1
  • 2

在这里插入图片描述

simplify(H.T.inv()*l)
  • 1

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/86787
推荐阅读
相关标签
  

闽ICP备14008679号