薄板样条插值TPS原理以及torch和opencv实现
- 1、薄板样条插值TPS原理
-
- 概述
- 原理以及公式推导
- 2、torch实现
- 3、opencv实现
1、薄板样条插值TPS原理
概述
薄板样条(Thin Plate Spline),简称TPS,是一种插值方法,可找到通过所有给定点的“最小弯曲”光滑曲面。因为它一般都是基于2D插值,所以经常用在在图像配准中,也可以用于图像扭曲变形(扩充图像)。在两张图像中找出N个匹配点,应用TPS可以将这N个点形变到对应位置,同时给出了整个空间的形变(插值)。
在使用TPS图像配准过程中,需要输入原始图像初始点(也就是变换前像素点的位置),和目标图像的目标点(也就是变换之后像素点在目标图像中的位置)。通常为两张图像上的m组匹配点,如P1(x1,y1)->P1’(x1’,y1’)、P2(x2,y2)->P2’(x2’,y2’)…Pm(xm,ym)->Pm’(xm’,ym’)。可以通过Shift、Surf、Orb,以及光流跟踪等算法获取匹配点对。我们以文字扭曲变形为例,TPS算法就是将原始图像中的红色点,变换到目标图像中绿色点的过程,在这个过程中要求图像平面所在薄板弯曲变形所需的能量最小,能量公式如图1。
原理以及公式推导
图1
TPS形变的目标是求解一个函数f,使得f(Pi)=Pi’ (1≤i≤n),并且弯曲能量函数最小,同时图像上的其它点也可以通过插值函数f得到很好的校正。
可以证明薄板样条的插值函数就是弯曲能量最小的函数:
f(x,y) = [[xi’],
[yi’]]
因此
令
则公式中的前半部分可以表示成以下形式:
后半部分中的U可以表示成以下形式:
首先看基础函数
的图像。
得到矩阵K
用K和P矩阵组合成L矩阵
令Y等于以下格式
则得
公式1
由上式得:
进而得到两个分解表达,第一个向量v表示的是目标点位置,向量o表示的是额外约束。
在上述表达式中,需要求解W和A矩阵,由公式1解得W和A矩阵:
到此,推到完毕。
2、torch实现
步骤解析:
- 先根据m个控制点求出w和a
1.1. 构造P、K、Y矩阵
1.2. 计算W、A
1.3. 生成网格grid,并计算K,P
1.4. 计算输出结果Y - 然后可以根据输入点p得到目标点p’。
p’ = p@a+k@w
其中@表示点乘p的维度为m×3、a的3×2、k的m×m、w的m×2 - 在计算w和a的过程,m的值为控制点的数量。
- 在推理阶段,m的值为所有的像素点的数量n(n=H*W)。
import cv2
import numpy as np
import random
import torch
from torchvision.transforms import ToTensor, ToPILImage
DEVICE = torch.device("cpu")
def choice3(img):
'''
产生波浪型文字
:param img:
:return:
'''
h, w = img.shape[0:2]
N = 5
pad_pix = 50
points = []
dx = int(w/ (N - 1))
for i in range( N):
points.append((dx * i, pad_pix))
points.append((dx * i, pad_pix + h))
#加边框
img = cv2.copyMakeBorder(img, pad_pix, pad_pix, 0, 0, cv2.BORDER_CONSTANT,
value=(int(img[0][0][0]), int(img[0][0][1]), int(img[0][0][2])))
#原点
source = np.array(points, np.int32)
source = source.reshape(1, -1, 2)
#随机扰动幅度
rand_num_pos = random.uniform(20, 30)
rand_num_neg = -1 * rand_num_pos
newpoints = []
for i in range(N