图像预处理之warpaffine与双线性插值及其高性能实现

图像预处理之warpaffine与双线性插值及其高性能实现

视频讲解:https://www.bilibili.com/video/BV1ZU4y1A7EG

代码Repo:https://github.com/shouxieai/tensorRT_Pro

本文为视频讲解的个人笔记。

warpaffine矩阵变换

对于坐标点的变换,我们通常考虑的是旋转、缩放、平移这三种变换。例如将点 P(x,y)P(x,y)P(x,y) 旋转 θ\thetaθ 度,缩放 scalescalescale 倍,平移 ox,oyox,oyox,oy 。warpaffine 将坐标点的旋转、缩放、平移三种操作集成为一个矩阵乘法运算。

旋转变换

我们先来看旋转,如图所示,我们要将点 P(x,y)P(x,y)P(x,y) 旋转到点 P′(x′,y′)P'(x',y')P(x,y) ,推导的过程很简单,我们要求的就是 x′,y′x',y'x,y 两点的坐标,将其转换为 m×cos(θ+α)m\times cos(\theta+\alpha)m×cos(θ+α)m×sin(θ+α)m\times sin(\theta+\alpha)m×sin(θ+α) ,再用公式展开,即得结果(详见图中公式):

{x′y′}={cos(θ)−sin(θ)sin(θ)cos(θ)}{xy}\left\{ \begin{array}{rc} x' \\ y' \end{array} \right\}= \left\{ \begin{array}{rc} cos(\theta) & -sin(\theta) \\ sin(\theta) & cos(\theta) \end{array} \right\} \left\{ \begin{array}{rc} x \\ y \end{array} \right\} {xy}={cos(θ)sin(θ)sin(θ)cos(θ)}{xy}
再考虑到我们在图像处理时的坐标系(如在 OpenCV 中的坐标系、常见目标检测的坐标系等)通常是原点在左上角,因此应该为:

{x′y′}={cos(θ)sin(θ)−sin(θ)cos(θ)}{xy}\left\{ \begin{array}{rc} x' \\ y' \end{array} \right\}= \left\{ \begin{array}{rc} cos(\theta) & sin(\theta) \\ -sin(\theta) & cos(\theta) \end{array} \right\} \left\{ \begin{array}{rc} x \\ y \end{array} \right\} {xy}={cos(θ)sin(θ)sin(θ)cos(θ)}{xy}
将旋转变换的矩阵记为 RRR ,则 P′=RPP'=RPP=RP

在这里插入图片描述

缩放变换

缩放变换比较简单,两坐标直接乘以缩放系数 scalescalescale 即可:

x′=x×scaley′=y×scalex'=x\times scale \\ y'=y\times scale x=x×scaley=y×scale
写成矩阵形式即:

{x′y′}={scale00scale}{xy}\left\{ \begin{array}{rc} x' \\ y' \end{array} \right\}= \left\{ \begin{array}{rc} scale & 0 \\ 0 & scale \end{array} \right\} \left\{ \begin{array}{rc} x \\ y \end{array} \right\} {xy}={scale00scale}{xy}
将缩放变换的变换矩阵记为 SSS,则:
P′=SPP'=SP P=SP
则旋转+缩放可以通过矩阵相乘写到同一个矩阵中:
{x′y′}={cos(θ)×scalesin(θ)×scale−sin(θ)×scalecos(θ)×scale}{xy}\left\{ \begin{array}{rc} x' \\ y' \end{array} \right\}= \left\{ \begin{array}{rc} cos(\theta) \times scale & sin(\theta) \times scale \\ -sin(\theta) \times scale & cos(\theta) \times scale \end{array} \right\} \left\{ \begin{array}{rc} x \\ y \end{array} \right\} {xy}={cos(θ)×scalesin(θ)×scalesin(θ)×scalecos(θ)×scale}{xy}
即:P′=SRPP'=SRPP=SRP

注意旋转和缩放顺序是随意的,不影响结果,这也可以通过代码来验证:

import numpy as nptheta = 0.8
scale = 2
rot = np.array([[np.cos(theta), np.sin(theta)],[-np.sin(theta), np.cos(theta)]
])sca = np.array([[scale, 0],[0, scale]
])print(np.allclose(rot @ sca, sca @ rot))
# 输出:True

平移变换

平移变换可以表示为:
x′=x+oxy′=y+oyx'=x+ox\\ y'=y+oy x=x+oxy=y+oy
矩阵形式:
{x′y′}={1001}{xy}+{oxoy}\left\{ \begin{array}{rc} x' \\ y' \end{array} \right\}= \left\{ \begin{array}{rc} 1 & 0 \\ 0 & 1 \end{array} \right\} \left\{ \begin{array}{rc} x \\ y \end{array} \right\} + \left\{ \begin{array}{rc} ox \\ oy \end{array} \right\} {xy}={1001}{xy}+{oxoy}
可以发现,平移变换直接写成矩阵形式,已经不是单纯的矩阵相乘了,而是多了一个很麻烦的相加的操作。这就很难与我们之前的缩放+旋转的操作合并到一起,该怎么办呢?

我们可以增加一个维度,将二维的非齐次的形式转换为三维的齐次的形式,即这个知乎回答中所提到的:增加一个维度之后,就可以在高维度通过线性变换来完成低维度的放射变换。(该回答将放射变换讲的很形象,推荐阅读)。

那么我们增加一维 (x,y,w)(x,y,w)(x,y,w),从而将点 PPP 表示为 P(xw,yw,1)P(\frac{x}{w},\frac{y}{w},1)P(wx,wy,1) ,这样平移变换就也可以表示为齐次矩阵乘的形式:

{x′y′w}={10ox01oy001}{xy1}\left\{ \begin{array}{rc} x' \\ y' \\ w \\ \end{array} \right\}= \left\{ \begin{array}{rc} 1 & 0 & ox \\ 0 & 1 & oy \\ 0 & 0 & 1 \end{array} \right\} \left\{ \begin{array}{rc} x \\ y \\ 1 \end{array} \right\} xyw=100010oxoy1xy1
最后我们得到缩放+旋转+平移变换的矩阵表示(注意平移与缩放、旋转的顺序是不能随意调换的):

{x′y′w}={cos(θ)×scalesin(θ)×scaleox−sin(θ)×scalecos(θ)×scaleoy001}{xy1}\left\{ \begin{array}{rc} x' \\ y' \\ w \end{array} \right\}= \left\{ \begin{array}{rc} cos(\theta) \times scale & sin(\theta) \times scale & ox \\ -sin(\theta) \times scale & cos(\theta) \times scale & oy \\ 0 & 0 & 1 \end{array} \right\} \left\{ \begin{array}{rc} x \\ y \\ 1 \end{array} \right\} xyw=cos(θ)×scalesin(θ)×scale0sin(θ)×scalecos(θ)×scale0oxoy1xy1
将平移变换的变换矩阵记为 RRR ,则:P′=TSRPP'=TSRPP=TSRP ,可以将整个 warpaffine 三个变换操作的矩阵记为 MMM ,即:M=TSR,P′=MPM=TSR,\ \ P'=MPM=TSR,  P=MP

warpaffine矩阵变换的反变换

  • 旋转矩阵的逆矩阵,即是其转置:R−1=RTR^{-1}=R^TR1=RT
  • 整个 warp affine 的三个变换求反变换,对整个变换矩阵求逆即可:P′=MP,P=M−1P′P'=MP,\ \ P=M^{-1}P'P=MP,  P=M1P

目标检测中的常用预处理

在目标检测中,我们的预处理通常是先对图像进行等比缩放,然后居中,多余部分填充,就类似下图所展示的。

在这里插入图片描述

我们将这个过程分为三个步骤:

  1. 等比缩放,矩阵 SSS 实现

在这里插入图片描述

  1. 将图片中心平移到左上坐标原点,矩阵 OOO 实现

在这里插入图片描述

  1. 将图片平移到目标位置的重心,矩阵 TTT 实现

在这里插入图片描述

三步拆分法,看似麻烦了一点,实际上可以方便我们后续可能会需要到的更复杂的变换(比如在 OOO 平移后加入旋转变换),并且便于记忆。

三步拆分法的矩阵表达:P′=TOSPP'=TOSPP=TOSP

我们直接写出具体的矩阵:
scale=min(Dst.widthOrigin.width,Dst.heightOrigin.height)M={scale0−scale×Origin.width2+Dst.width20scale−scale×Origin.height2+Dst.height2}scale = min(\frac{Dst.width}{Origin.width}, \frac{Dst.height}{Origin.height}) \\ \\ M = \left\{ \begin{array}{ll} scale & 0 & -\frac{scale \times Origin.width}{2} + \frac{Dst.width}{2} \\ 0 & scale & -\frac{scale \times Origin.height}{2} + \frac{Dst.height}{2} \\ \end{array} \right\} scale=min(Origin.widthDst.width,Origin.heightDst.height)M={scale00scale2scale×Origin.width+2Dst.width2scale×Origin.height+2Dst.height}

{x′y′}={scale0−scale×Origin.width2+Dst.width20scale−scale×Origin.height2+Dst.height2}{xy1}\left\{ \begin{array}{ll} x' \\ y' \\ \end{array} \right\}= \left\{ \begin{array}{ll} scale & 0 & -\frac{scale \times Origin.width}{2} + \frac{Dst.width}{2} \\ 0 & scale & -\frac{scale \times Origin.height}{2} + \frac{Dst.height}{2} \\ \end{array} \right\} \left\{ \begin{array}{ll} x \\ y \\ 1 \end{array} \right\} {xy}={scale00scale2scale×Origin.width+2Dst.width2scale×Origin.height+2Dst.height}xy1

逆变换:
k=scaleb1=−scale×Origin.width2+Dst.width2b2=−scale×Origin.height2+Dst.height2x′=kx+b1y′=ky+b2x=x′−b1k=x′×1k+(−b1k)y=y′−b2k=y′×1k+(−b2k)M−1={1k0−b1k01k−b2k}k = scale \\ b1 = -\frac{scale \times Origin.width}{2} + \frac{Dst.width}{2} \\ b2 = -\frac{scale \times Origin.height}{2} + \frac{Dst.height}{2} \\ x' = kx + b1 \\ y' = ky + b2 \\ x = \frac{x' - b1}{k} = x'\times \frac{1}{k} + (-\frac{b1}{k}) \\ y = \frac{y' - b2}{k} = y'\times \frac{1}{k} + (-\frac{b2}{k}) \\ M^{-1} = \left\{ \begin{array}{ll} \frac{1}{k} & 0 & -\frac{b1}{k} \\ 0 & \frac{1}{k} & -\frac{b2}{k} \\ \end{array} \right\} k=scaleb1=2scale×Origin.width+2Dst.widthb2=2scale×Origin.height+2Dst.heightx=kx+b1y=ky+b2x=kxb1=x×k1+(kb1)y=kyb2=y×k1+(kb2)M1={k100k1kb1kb2}

warpaffine正逆变换代码实验

TODO

双线性插值

线性插值

距离目标点越远,影响就越小,因此权重是对面的距离占比。

如目标点距离冷水 0.6,距离热水 0.4,则冷水权重为 0.4 ,热水权重为 0.6 。

在这里插入图片描述

p0 = 20    # 冷水
p1 = 100   # 热水
pos = 0.6  # 应该多少度value = (1 - pos) * p0 + pos * p1
print(value)

双线性插值

线性插值的二维版本,原理一直,只是权重从计算长度占比改为计算面积占比。

调色板,红点对目标点(紫点)的影响权重即为对面的面积(红框面积)占总面积的比例。

在这里插入图片描述

高性能实现

为什么高性能?

  • 我们在操作每个像素的过程中,可以将模型需要的像素级预处理(如减均值除标准差、除以255、BGR通道转换等)一并做了,避免多个操作分开来反复对每个像素进行循环访问这种低效行为。
  • warpaffine 极其适合通过 cuda 核函数进行 GPU 加速。可以参考 repo 中的 preprocess_kernel.cu 。完整代码比较长这里就不放了。
  • 以下是 warpaffine 双线性插值的 Python 实现,供参考:
def pyWarpAffine(image, M, dst_size, constant=(0, 0, 0)):# 注意输入的M矩阵格式,是Origin->Dst# 而这里需要的是Dst->Origin,所以要取逆矩阵M = cv2.invertAffineTransform(M)constant = np.array(constant)ih, iw   = image.shape[:2]dw, dh   = dst_sizedst      = np.full((dh, dw, 3), constant, dtype=np.uint8)irange   = lambda p: p[0] >= 0 and p[0] < iw and p[1] >= 0 and p[1] < ihfor y in range(dh):for x in range(dw):homogeneous = np.array([[x, y, 1]]).Tox, oy = M @ homogeneouslow_ox = int(np.floor(ox))low_oy = int(np.floor(oy))high_ox = low_ox + 1high_oy = low_oy + 1# p0     p1#      o# p2     p3pos = ox - low_ox, oy - low_oyp0_area = (1 - pos[0]) * (1 - pos[1])p1_area = pos[0] * (1 - pos[1])p2_area = (1 - pos[0]) * pos[1]p3_area = pos[0] * pos[1]p0 = low_ox, low_oyp1 = high_ox, low_oyp2 = low_ox, high_oyp3 = high_ox, high_oyp0_value = image[p0[1], p0[0]] if irange(p0) else constantp1_value = image[p1[1], p1[0]] if irange(p1) else constantp2_value = image[p2[1], p2[0]] if irange(p2) else constantp3_value = image[p3[1], p3[0]] if irange(p3) else constantdst[y, x] = p0_area * p0_value + p1_area * p1_value + p2_area * p2_value + p3_area * p3_value# 交换bgr  rgb# normalize ->  -mean /std# 1行代码实现normalize , /255.0# bgr bgr bgr -> bbb ggg rrr# focus# focus offset, 1行代码实现focusreturn dstcat1 = cv2.imread("cat1.png")
#acat1_cv, M, inv = align(cat1, (100, 100))
M = cv2.getRotationMatrix2D((0, 0), 30, 0.5)
acat1_cv = cv2.warpAffine(cat1, M, (100, 100))
acat1_py = pyWarpAffine(cat1, M, (100, 100))plt.figure(figsize=(10, 10))
plt.subplot(1, 2, 1)
plt.title("OpenCV")
plt.imshow(acat1_cv[..., ::-1])plt.subplot(1, 2, 2)
plt.title("PyWarpAffine")
plt.imshow(acat1_py[..., ::-1])

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/532477.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

sed 简明教程

sed 简明教程 转自&#xff1a;https://coolshell.cn/articles/9104.html awk于1977年出生&#xff0c;今年36岁本命年&#xff0c;sed比awk大2-3岁&#xff0c;awk就像林妹妹&#xff0c;sed就是宝玉哥哥了。所以 林妹妹跳了个Topless&#xff0c;他的哥哥sed坐不住了&#xf…

[深度][PyTorch] DDP系列第一篇:入门教程

[深度][PyTorch] DDP系列第一篇&#xff1a;入门教程 转自&#xff1a;[原创][深度][PyTorch] DDP系列第一篇&#xff1a;入门教程 概览 想要让你的PyTorch神经网络在多卡环境上跑得又快又好&#xff1f;那你definitely需要这一篇&#xff01; No one knows DDP better than I…

[深度][PyTorch] DDP系列第二篇:实现原理与源代码解析

[深度][PyTorch] DDP系列第二篇&#xff1a;实现原理与源代码解析 转自&#xff1a;https://zhuanlan.zhihu.com/p/187610959 概览 想要让你的PyTorch神经网络在多卡环境上跑得又快又好&#xff1f;那你definitely需要这一篇&#xff01; No one knows DDP better than I do! …

[深度][PyTorch] DDP系列第三篇:实战与技巧

[深度][PyTorch] DDP系列第三篇&#xff1a;实战与技巧 转自&#xff1a;https://zhuanlan.zhihu.com/p/250471767 零. 概览 想要让你的PyTorch神经网络在多卡环境上跑得又快又好&#xff1f;那你definitely需要这一篇&#xff01; No one knows DDP better than I do! – – …

机器学习:系统设计与实现 分布式训练

机器学习系统:设计与实现 分布式训练 转自&#xff1a;https://openmlsys.github.io/chapter_distributed_training/index.html 随着机器学习的进一步发展&#xff0c;科学家们设计出更大型&#xff0c;更多功能的机器学习模型&#xff08;例如说&#xff0c;GPT-3&#xff09;…

从零Makefile落地算法大项目,完整案例教程

从零Makefile落地算法大项目&#xff0c;完整案例教程 转自&#xff1a;从零Makefile落地算法大项目&#xff0c;完整案例教程 作者&#xff1a;手写AI 前言 在这里&#xff0c;你能学到基于Makefile的正式大项目的使用方式和考虑&#xff0c;相信我&#xff0c;其实可以很简单…

PyTorch扩展自定义PyThonC++(CUDA)算子的若干方法总结

PyTorch扩展自定义PyThon/C(CUDA)算子的若干方法总结 转自&#xff1a;https://zhuanlan.zhihu.com/p/158643792 作者&#xff1a;奔腾的黑猫 在做毕设的时候需要实现一个PyTorch原生代码中没有的并行算子&#xff0c;所以用到了这部分的知识&#xff0c;再不总结就要忘光了 &a…

给 Python 算法插上性能的翅膀——pybind11 落地实践

给 Python 算法插上性能的翅膀——pybind11 落地实践 转自&#xff1a;https://zhuanlan.zhihu.com/p/444805518 作者&#xff1a;jesonxiang&#xff08;向乾彪&#xff09;&#xff0c;腾讯 TEG 后台开发工程师 1. 背景 目前 AI 算法开发特别是训练基本都以 Python 为主&…

chrome自动提交文件_收集文档及提交名单统计

知乎文章若有排版问题请见谅&#xff0c;原文放在个人博客中【欢迎互踩&#xff01;】文叔叔文档收集使用动机在我们的学习工作中&#xff0c;少不了要让大家集体提交文件的情况&#xff0c;举个最简单的例子&#xff1a;收作业。 传统的文件收集流程大致是&#xff1a;群内发出…

惠普800g1支持什么内存_惠普黑白激光打印机哪种好 惠普黑白激光打印机推荐【图文详解】...

打印机的出现让我们在生活和日常工作中变得越来越方便&#xff0c;不过随着科技的发展&#xff0c;打印机的类型也变得非常多&#xff0c;其中就有黑白激光打印机&#xff0c;而黑白激光打印机的品牌也有很多&#xff0c;比如我们的惠普黑白激光打印机&#xff0c;今天小编就给…

控制台输出颜色控制

控制台输出颜色控制 转自&#xff1a;https://cloud.tencent.com/developer/article/1142372 前端时间&#xff0c;写了一篇 PHP 在 Console 模式下的进度显示 &#xff0c;正好最近的一个数据合并项目需要用到控制台颜色输出&#xff0c;所以就把相关的信息整理下&#xff0c;…

idea连接跳板机_跳板机服务(jumpserver)

一、跳板机服务作用介绍1、有效管理用户权限信息2、有效记录用户登录情况3、有效记录用户操作行为二、跳板机服务架构原理三、跳板机服务安装过程第一步&#xff1a;安装跳板机依赖软件yum -y install git python-pip mariadb-devel gcc automake autoconf python-devel readl…

【详细图解】再次理解im2col

【详细图解】再次理解im2col 转自&#xff1a;https://mp.weixin.qq.com/s/GPDYKQlIOq6Su0Ta9ipzig 一句话&#xff1a;im2col是将一个[C,H,W]矩阵变成一个[H,W]矩阵的一个方法&#xff0c;其原理是利用了行列式进行等价转换。 为什么要做im2col? 减少调用gemm的次数。 重要…

反思 大班 快乐的机器人_幼儿园大班教案《快乐的桌椅》含反思

大班教案《快乐的桌椅》含反思适用于大班的体育主题教学活动当中&#xff0c;让幼儿提高协调性和灵敏性&#xff0c;创新桌椅的玩法&#xff0c;正确爬的方法&#xff0c;学会匍匐前进&#xff0c;快来看看幼儿园大班《快乐的桌椅》含反思教案吧。幼儿园大班教案《快乐的桌椅》…

DCN可形变卷积实现1:Python实现

DCN可形变卷积实现1&#xff1a;Python实现 我们会先用纯 Python 实现一个 Pytorch 版本的 DCN &#xff0c;然后实现其 C/CUDA 版本。 本文主要关注 DCN 可形变卷积的代码实现&#xff0c;不会过多的介绍其思想&#xff0c;如有兴趣&#xff0c;请参考论文原文&#xff1a; …

蓝牙耳机声音一顿一顿的_线控耳机党阵地转移成功,OPPO这款TWS耳机体验满分...

“你看到我手机里3.5mm的耳机孔了吗”&#xff0c;这可能是许多线控耳机党最想说的话了。确实&#xff0c;如今手机在做“减法”&#xff0c;而厂商们首先就拿3.5mm耳机孔“开刀”&#xff0c;我们也丧失了半夜边充电边戴耳机打游戏的乐趣。竟然如此&#xff0c;那如何在耳机、…

AI移动端优化之Im2Col+Pack+Sgemm

AI移动端优化之Im2ColPackSgemm 转自&#xff1a;https://blog.csdn.net/just_sort/article/details/108412760 这篇文章是基于NCNN的Sgemm卷积为大家介绍Im2ColPackSgemm的原理以及算法实现&#xff0c;希望对算法优化感兴趣或者做深度学习模型部署的读者带来帮助。 1. 前言 …

elementui的upload组件怎么获取上传的文本流、_抖音feed流直播间引流你还不会玩?实操讲解...

本文由艾奇在线明星优化师写作计划出品在这个全民惊恐多灾多难且带有魔幻的2020&#xff0c;一场突如其来的疫情改变了人们很多消费习惯&#xff0c;同时加速了直播电商的发展&#xff0c;现在直播已经成为商家必争的营销之地&#xff0c;直播虽然很火&#xff0c;但如果没有流…

FFmpeg 视频处理入门教程

FFmpeg 视频处理入门教程 转自&#xff1a;https://www.ruanyifeng.com/blog/2020/01/ffmpeg.html 作者&#xff1a; 阮一峰 日期&#xff1a; 2020年1月14日 FFmpeg 是视频处理最常用的开源软件。 它功能强大&#xff0c;用途广泛&#xff0c;大量用于视频网站和商业软件&…

checkbox wpf 改变框的大小_【论文阅读】倾斜目标范围框(标注)的终极方案

前言最常用的斜框标注方式是在正框的基础上加一个旋转角度θ&#xff0c;其代数表示为(x_c,y_c,w,h,θ)&#xff0c;其中(x_c,y_c )表示范围框中心点坐标&#xff0c;(w,h)表示范围框的宽和高[1,2,7]。对于该标注方式&#xff0c;如果将w和h的值互换&#xff0c;再将θ加上或者…