最近项目用到了tps算法,opencv2封装的tps实现起来比较慢,于是用pytorch实现了一下,可以支持gpu加速,就很nice了,在这里记录一下!

1. 简介

薄板样条函数(TPS)是一种很常见的插值方法。因为它一般都是基于2D插值,所以经常用在在图像配准中。在两张图像中找出N个匹配点,应用TPS可以将这N个点形变到对应位置,同时给出了整个空间的形变(插值)。

2. 实现

1. opencv的tps使用

import cv2
import numpy as np
import random
import torch
from torchvision.transforms import ToTensor, ToPILImageDEVICE = torch.device("cpu")def choice3(img):'''产生波浪型文字:param img::return:'''h, w = img.shape[0:2]N = 5pad_pix = 50points = []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_posnewpoints = []for i in range(N):rand = np.random.choice([rand_num_neg, rand_num_pos], p=[0.5, 0.5])if(i == 1):nx_up = points[2 * i][0]ny_up = points[2 * i][1] + randnx_down = points[2 * i + 1][0]ny_down = points[2 * i + 1][1] + randelif (i == 4):rand = rand_num_neg if rand > 1 else rand_num_posnx_up = points[2 * i][0]ny_up = points[2 * i][1] + randnx_down = points[2 * i + 1][0]ny_down = points[2 * i + 1][1] + randelse:nx_up = points[2 * i][0]ny_up = points[2 * i][1]nx_down = points[2 * i + 1][0]ny_down = points[2 * i + 1][1]newpoints.append((nx_up, ny_up))newpoints.append((nx_down, ny_down))#target点target = np.array(newpoints, np.int32)target = target.reshape(1, -1, 2)#计算matchesmatches = []for i in range(1, 2*N + 1):matches.append(cv2.DMatch(i, i, 0))return source, target, matches, imgdef norm(points_int, width, height):"""将像素点坐标归一化至 -1 ~ 1"""points_int_clone = torch.from_numpy(points_int).detach().float().to(DEVICE)x = ((points_int_clone * 2)[..., 0] / (width - 1) - 1)y = ((points_int_clone * 2)[..., 1] / (height - 1) - 1)return torch.stack([x, y], dim=-1).contiguous().view(-1, 2)class TPS(torch.nn.Module):def __init__(self):super().__init__()def forward(self, X, Y, w, h, device):""" 计算grid"""grid = torch.ones(1, h, w, 2, device=device)grid[:, :, :, 0] = torch.linspace(-1, 1, w)grid[:, :, :, 1] = torch.linspace(-1, 1, h)[..., None]grid = grid.view(-1, h * w, 2)""" 计算W, A"""n, k = X.shape[:2]device = X.deviceZ = torch.zeros(1, k + 3, 2, device=device)P = torch.ones(n, k, 3, device=device)L = torch.zeros(n, k + 3, k + 3, device=device)eps = 1e-9D2 = torch.pow(X[:, :, None, :] - X[:, None, :, :], 2).sum(-1)K = D2 * torch.log(D2 + eps)P[:, :, 1:] = XZ[:, :k, :] = YL[:, :k, :k] = KL[:, :k, k:] = PL[:, k:, :k] = P.permute(0, 2, 1)Q = torch.solve(Z, L)[0]W, A = Q[:, :k], Q[:, k:]""" 计算U """eps = 1e-9D2 = torch.pow(grid[:, :, None, :] - X[:, None, :, :], 2).sum(-1)U = D2 * torch.log(D2 + eps)""" 计算P """n, k = grid.shape[:2]device = grid.deviceP = torch.ones(n, k, 3, device=device)P[:, :, 1:] = grid# grid = P @ A + U @ Wgrid = torch.matmul(P, A) + torch.matmul(U, W)return grid.view(-1, h, w, 2)if __name__=='__main__':# 弯曲水平文本img = cv2.imread('data/test.jpg', cv2.IMREAD_COLOR)source, target, matches, img = choice3(img)# #opencv版tps# tps = cv2.createThinPlateSplineShapeTransformer()# tps.estimateTransformation(source, target, matches)# img = tps.warpImage(img)# cv2.imshow('test.png', img)# cv2.imwrite('test.png', img)# cv2.waitKey(0)#torch实现tpsten_img = ToTensor()(img).to(DEVICE)h, w = ten_img.shape[1], ten_img.shape[2]ten_source = norm(source, w, h)ten_target = norm(target, w, h)tps = TPS()warped_grid = tps(ten_target[None, ...], ten_source[None, ...], w, h, DEVICE)   #这个输入的位置需要归一化,所以用normten_wrp = torch.grid_sampler_2d(ten_img[None, ...], warped_grid, 0, 0)new_img_torch = np.array(ToPILImage()(ten_wrp[0].cpu()))cv2.imshow('test.png', new_img_torch)cv2.imwrite('test.png', new_img_torch)cv2.waitKey(0)

3. 效果

  • 贴个效果图对比:

上图可以看出,pytorch实现与cv2的tps的效果完全对齐,所以重点看耗时,接下来贴耗时的对比图(差距还是蛮大的,图片越大差距越大)

如果对你有帮助的话,希望给个赞,谢谢~


参考1:TPS 薄板样条插值 python的opencv实现
注,这个参考可以初步了解使用cv2的tps使用,但是具体细节上还存在错误

参考2:薄板样条函数(Thin plate splines)的讨论与分析
参考3:数值方法——薄板样条插值(Thin-Plate Spline)

薄板样条插值(Thin plate splines)的实现与使用相关推荐

  1. 薄板样条插值---Thin plate spline (TPS)

    薄板样条插值 薄板样条插值---Thin plate spline (TPS) 公式 样条插值示例 未来工作 薄板样条插值-Thin plate spline (TPS) 由于研究内容原因,最近在研究 ...

  2. matlab薄板样条函数,薄板样条函数(Thin plate splines)的讨论与分析

    薄板样条函数(TPS)是一种很常见的插值方法.因为它一般都是基于2D插值,所以经常用在在图像配准中.在两张图像中找出N个匹配点,应用TPS可以将这N个点形变到对应位置,同时给出了整个空间的形变(插值) ...

  3. 薄板样条函数Thin Plate Spline

    TPS薄板样条函数是一种插值算法,用于图像变形(image warping)等,通过少量控制点就可以驱动图像进行变化 我在自己的课题中要用到的是基于2D插值,图像配准.两张图像中已知有N个匹配点,应用 ...

  4. Thin Plate Spline (薄板样条函数)

    原网址:http://blog.csdn.net/swimmingfish2004/article/details/7666087 对于"Given corresponding points ...

  5. 关于Thin Plate Spline (薄板样条函数)

    最近在看AAM(主动表现模型)时看到了,对于"Given corresponding points in two images, how do we warp one into the ot ...

  6. 薄板样条函数 matlab,基于薄板样条插值图像配准的Matlab实现

    Date: 2015-06-30 21:53 1. 基本数学描述 薄板样条(Thin Plate Spline)映射根据两幅相关图像中的对应控制点集来决定一个变形函数.它寻找通过所有给定点的饶度最小的 ...

  7. [经典的图像warping方法] Thin Plate Spline: TPS理论和代码详解

    0. 前言 2022年没有新写什么博客, 主要精力都在搞论文. 今年开始恢复! 本文的目标是详细分析一个经典的基于landmark(文章后面有时也称之为控制点control point)的图像warp ...

  8. Thin Plate Spline TPS薄板样条变换基础理解

    什么是图像扭曲问题? 给定控制点​​​​​​​和相应位移点稀疏对应集,我们需要找到一个映射,且两点之间的尽可能平滑. 一维空间举例,绿色为对应集,需找到蓝色曲线映射,满足形变后控制点重合且之间连线平滑 ...

  9. 基于TPS(Thin Plate Spines)的STN网络的PyTorch实现

    基于TPS(Thin Plate Spines)的STN网络是OCR领域CVPR论文<Robust Scene Text Recognition with Automatic Rectifica ...

最新文章

  1. Spring源码分析之 lazy-init 实现原理
  2. 2019小程序没必要做了_2019微信小程序的发展前景怎么样?有必要开发微信小程序吗?...
  3. ant使用指南详细入门教程
  4. PCB设计中的问题整理
  5. matlab 双音多频 接收端检测到的号码,信号语音论文,关于基于MATLAB的双音多频信号识别相关参考文献资料-免费论文范文...
  6. python 网络编程 异步io_异步IO实现 小例(程序+驱动程序)
  7. linux gcc编译只能编译一条,请教一个gcc编译器的问题啊
  8. 操作系统 第二章 进程管理
  9. MySQL【第三篇】数据类型
  10. Android中文API(98)—— ContextMenu.ContextMenuInfo
  11. 计算出 3 至 1000 范围内最大的十个素数,放入数组中,并计算出其累加和。
  12. 类比菜鸟全国仓配网络来学习CDN
  13. 八重州8900如何解锁_八重贵族怪胎之路
  14. 微信公众号支付开发全过程
  15. 小甲鱼c语言照片,【跟着小甲鱼学C语言】P14 给大家介绍对象
  16. ArcGIS网络分析之数据组织、连通性设置
  17. 2020,只争朝夕,不负韶华
  18. VS报错:没有足够的内存继续执行程序
  19. “创新雷神号”卫星成功发射,华为云分布式云原生“天地一体”首次组网成功
  20. 如何使用ssh连接windows?

热门文章

  1. 03-肯德基点餐:抽象工厂模式
  2. 百度之星资格赛1003:度度熊与邪恶大魔王
  3. 【oracle11g,17】存储结构: 段的类型,数据块(行连接、行迁移,块头),段的管理方式,高水位线...
  4. Asp.Net的Forms验证,解决Cookie和Seesion失效时间。
  5. MyBatis 多表关联相同字段的解决方案
  6. 【Python笔记】网络爬虫——常用框架介绍以及 Scrapy 框架使用
  7. Linux系统管理(6)——Linux下启动Redis服务的几种方法
  8. [转]caffe-ssd中 net.forward()返回值
  9. Tomcat绑定jre
  10. java AST 表达式_Atitti.java exp ast java表达式语法ast构造器