薄板样条插值TPS原理以及torch和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’]]
在这里插入图片描述
因此
在这里插入图片描述
在这里插入图片描述
则公式中的前半部分可以表示成以下形式:
Pn×3 A3×2=
后半部分中的U可以表示成以下形式:
在这里插入图片描述
首先看基础函数在这里插入图片描述
的图像。
在这里插入图片描述
得到矩阵K
在这里插入图片描述
用K和P矩阵组合成L矩阵
在这里插入图片描述
令Y等于以下格式
在这里插入图片描述
则得
在这里插入图片描述
公式1
由上式得:
在这里插入图片描述
进而得到两个分解表达,第一个向量v表示的是目标点位置,向量o表示的是额外约束。
在这里插入图片描述
在上述表达式中,需要求解W和A矩阵,由公式1解得W和A矩阵:

在这里插入图片描述
到此,推到完毕。

2、torch实现

步骤解析:

  1. 先根据m个控制点求出w和a
    1.1. 构造P、K、Y矩阵
    1.2. 计算W、A
    1.3. 生成网格grid,并计算K,P
    1.4. 计算输出结果Y
  2. 然后可以根据输入点p得到目标点p’。
    p’ = p@a+k@w
    其中@表示点乘p的维度为m×3、a的3×2、k的m×m、w的m×2
  3. 在计算w和a的过程,m的值为控制点的数量。
  4. 在推理阶段,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):
        rand = np.random.choice([rand_num_neg, rand_num_pos
  • 27
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值