当前位置: 首页 > news >正文

图片动画化应用中的动作分解方法

在这里插入图片描述

作者 | FesianXu

前言

最近基于AI的换脸应用非常的火爆,同时也引起了新一轮的网络伦理大讨论。如果光从技术的角度看,对于视频中的人体动作信息,通常可以通过泰勒展开分解成零阶运动信息与一阶运动信息,如文献[1,2]中提到的,动作的分解可以为图片动画化提供很好的光流信息,而图片动画化是提供换脸技术的一个方法。笔者在本文将会根据[1,2]文献中的内容,对其进行笔记和个人理解的探讨。 如有谬误请联系指出,转载请联系作者并注明出处,谢谢


注意:本文只是基于[1,2]文献的内容阐述思路,为了行文简练,去除了某些细节,如有兴趣,请读者自行翻阅对应论文细读。

Δ\DeltaΔ 本文使用术语纪要

<1>. 指引视频(Guided Video),驱动视频(Driving Video):指的是给定的用于提供动作信息的视频,该视频负责驱动,引导图片的动态信息,这两个术语在本文中将会视场合混用。

<2>. 静态图(Source Image, Source Frame):需要被驱动的图片,其主体类别通常需要和指引视频中的类别一致,主体身份可以不同。

<3>. 泰勒展开(Taylor Expansion):将复杂的非线性函数通过展开的方式变换成若干项的线性组合。

<4>. 变形(deformation):指的是通过某些控制点去操控一个图片的某些部位,使得图片像素发生移动或者插值,从而形成一定程度空间上变化。

<5>. 主体(entity):指的是图片或者视频中的活动主体,该主体不一定是人体,也可能是其他任意的物体。这里要明确的是本文提到的 主体类别(entity category) 和 主体身份(entity identity),主体身份不同于类别,比如都是人脸,一个张三的人脸,而另一个是李四的人脸。

<6>. 稀疏光流图(Sparse Optical Flow Map):表示不同帧之间,稀疏的关键点之间的空间变化,是一个向量场。

<7>. 密集光流图(Dense Optical Flow Map):表示不同帧之间,每个像素之间的空间变化,是一个向量场。


从图片动画化说起

我们知道最近的基于AI的换脸应用非常火爆,也引起了一轮轮关于AI使用的伦理大讨论,这从侧面反映了AI技术应用在我们日常生活的渗透。如Fig 1.1所示,给定一个指引视频,让一张静态图片跟随着该视频表演其中的表情(或者动作),这种技术的主要框架在于需要分离指引视频中的动作信息(motion)和外观信息(appearance),将提取出的动作信息以某种形式添加到静态图上,让静态图达到一定程度的变形(deformation),以达到图片动态化表演特定动作的目的。

在这里插入图片描述

Fig 1.1 换脸的例子。给定一个静态的图片和一段相对应主体类别的(比如同样是人脸)的指引视频,我们可以让图片跟着视频一起动起来,达到以假乱真的目的。原图出自[10]。

fashion-teaser

Fig 1.2 不仅仅是人脸替换,图片动画化可以应用在主体类别一致的其他主体中。原图出自[10]。

这类型的工作可以称之为图片动画化 (image animation),指的是给定一张具有某个主体的静态图(Source Image)(主体不一定是人体,如Fig 1.2所示,不过我们这里主要以人体做例子),再给定一个由该主体表演某个动作的视频,一般称之为驱动视频(Driving Video),让静态图跟随着驱动视频的动作“活动”起来。注意到静态图和驱动视频中的主体是同一类型的主体,但是身份可能是不同的,比如都是人脸,但是不是同一个人的人脸。如Fig 1.3所示,给定了一个驱动视频,其主体是一个人脸的表情序列,给定了一个静态图,主体是一个不同身份的人,然后任务期望提取出序列中的动作信息,期望以某种方法添加到静态图上,使得静态图可以通过像素变形的方式,形成具有指定动作,但是主体身份和静态图一致的新的动作序列。

image_animation

Fig 1.3 图片动画化的例子。给定一个驱动视频,和若干不同的静态图,从驱动视频中提取出人脸的运动信息,将运动信息以某种方式“添加”到静态图上,以达到让静态图跟随着驱动视频活动起来的目的。

当然,该任务不一定被局限在人脸上,如Fig 1.2所示,事实上,只要输入驱动视频和静态图的主体类别一致,就可以通过某些自监督的方法进行动作信息提取,并且接下来进行动作信息迁移到目标静态图上的操作。

我们现在已经对图片动画化有了基本的认识,那么从技术上看,这整个任务的难点在于哪儿呢?主要在于以下几点:

  1. 如何表征运动信息?
  2. 如何提取驱动视频中的运动信息?
  3. 如何将提取到的动作信息添加到静态图中,让静态图变形?

通常来说,表征一个主体的运动信息可以通过密集光流图的方式表达,光流(optical flow)[5] 表示的是某个局部运动的速度和方向,简单地可以理解为在时间很短的两个连续帧的某个局部,相对应像素的变化情况。如Fig 1.4所示,如果计算(a)(b)两帧关于蓝色框内的光流,我们可以得到如同(c)所示的光流图,表征了这个“拔箭”动作的局部运动速度和方向,因此是一个向量场,我们通常可以用F∈RH×W×2\mathcal{F} \in \mathbb{R}^{H \times W \times 2}FRH×W×2表示,其中的H×WH \times WH×W表示的是局部区域的空间尺寸,维度2表示的是二维空间(Δx,Δy)(\Delta x, \Delta y)(Δx,Δy)偏移。如果该局部区域的每一个像素都计算光流图,那么得到的光流图就称之为 密集光流图(Dense Optical Flow Map),如Fig 1.4 (c)所示。密集光流图中的每一个像素对应的向量方向,提供了从一个动作转移到下一个动作所必要的信息,是图片动画化过程中的必需信息。

optical_flow

Fig 1.4 (a)(b)两张图是连续的两帧,而(c)是对蓝色框区域进行计算得到的光流图,表征了运动的速度和方向。原图出自[4]。

如果能够给出某个运动的密集光流图,那么就可以根据每个像素对应在光流图中的向量方向与大小对像素进行位移插值后,实现图像的变形的过程。然而,在图片动画化过程中,我们的输入通常如Fig 1.5所示,其静态图和驱动视频中的某一帧(称之为驱动帧)之间的动作差别很大,而且主体的身份还不一定一致,能确定的只有 一点,就是: 稀疏的关键点可以视为是一一配对的。 如Fig 1.3所示,蓝色点是人体的稀疏关键点,通常存在一对一的配对映射(暂时不考虑遮挡),如黄色虚线所示,这种稀疏关键点的映射图,我们称之为 稀疏光流图 (Sparse Optical Flow Map)。我们接下来介绍的文章,都是 **从不同方面考虑从稀疏光流图推理出密集光流图,从而指引图片变形的。 **

sparse_kp_mapping

Fig 1.5 通常输入的是差别较大的静态图(Source)和驱动视频中的某一帧(Driving Frame),蓝点表示的是稀疏的关键点,黄色虚线表示的是对应关键点的配对。

到此为止,我们之前讨论了如何定义一个动作的运动信息,也就是用密集光流图表示。同时,我们也分析了一种情况,在实际任务中,很难直接得到密集光流图,因此需要从一对一配对的稀疏光流图中加入各种先验知识,推理得到密集光流图。我们接下来的章节讨论如何添加这个先验知识。

为了以后章节的讨论方便,我们给出图片动画化模型的基本结构,如Fig 1.6所示,需要输入的是驱动视频和静态图,静态图具有和驱动视频相同的主体类别(比如都是人)但是身份可以不同(比如是不同的人),期望生成具有和静态图相同身份和主体,动作和驱动视频一致的视频,通常是提取驱动视频中每帧的动作信息,结合静态图生成期望的视频帧,在拼接成最终的视频输出。

image_animation_framework

Fig 1.6 图片动画化的基本框图,其中Monkey-Net是一种图片动画化的模型,可以替换成其他模型。一般只需要输入驱动视频和某张具有同样主体类别的静态图,通过提取驱动视频中每一帧的动作信息,结合静态图就可以生成具有静态图主体身份和类别,而且具有驱动视频同一个动作的“生成视频”。

无监督关键点提取

在继续讨论密集光流图提取之前,我们首先描述下如何提取稀疏光流信息,也即是稀疏的关键点信息,如Fig 1.5所示。当然,对于人体而言,目前已经有很多研究可以进行人体姿态估计,比如OpenPose [6],AlphaPose [7]等,这些研究可以提取出相对不错的人体关键点。就人脸这块的关键点提取而言,也有很多不错的研究[8],可以提取出相对不错的人脸稀疏或者密集关键点,如Fig 2.1所示。

face-alignment-adrian

Fig 2.1 人脸关键点提取方法已经日渐成熟,效果已经相当不错了,原图出自[9]。

但是,我们注意到,为了提取人体或者人脸的关键点,目前的大多数方法都需要依赖于大规模的人体/人脸标注数据集,这个工作量非常大,因此,假如我们需要对某些非人脸/人体的图片进行图片动画化,比如Fig 2.2所示的动画风格的马,我们将无法通过监督学习的方式提取出关键点,因为没有现存的关于这类型数据的数据集。为了让图片动画化可以泛化到人体/人脸之外更广阔的应用上,需要提出一种无监督提取特定主体物体关键点的方法。

mgif-teaser

Fig 2.2 动画风格的马的图片动画化,现存的研究并没有关于这类型数据的关键点提取,也没有相关的数据集,因此依赖于监督学习,在这种数据中提取关键点是一件困难的问题。原图出自[10]。

文献[1,2,11]利用了一种无监督的关键点提取方法,这里简单介绍一下,为之后的章节提供铺垫。如Fig 2.3所示,对于输入的单帧RGB图片I∈RH×W×3\mathbf{I} \in \mathbb{R}^{H \times W \times 3}IRH×W×3来说,利用U-net [12]提取出KKK个热值图Hk∈[0,1]H×W,k∈[1,⋯,K]H_k \in [0,1]^{H \times W}, k \in [1,\cdots,K]Hk[0,1]H×W,k[1,,K],每kkk个热值图表示了第kkk个关节点的分布情况。当然,U-net的最后一层需要用softmax层作为激活层,这样解码器的输出才能解释为每个关键点的置信图(confidence map)。

kps_detector

Fig 2.3 用U-net分别提取静态图和驱动帧的关键点。

然而,我们还需要从置信图中计算得到关键点的中心位置和关节点的方差1(方差以超像素的角度,表示了对关键点预测的可靠性),因此用高斯分布去对置信图进行拟合,得到均值和方差。对于每个关键点的置信图Hk∈[0,1]H×WH_k \in [0,1]^{H \times W}Hk[0,1]H×W,我们有:
hk=∑p∈UHk[p]pΣk=∑p∈UHk[p](p−hk)(p−hk)T(2.1)\begin{aligned} \mathbf{h}_k &= \sum_{p\in\mathcal{U}}H_k[p]p \\ \Sigma_k &= \sum_{p\in\mathcal{U}}H_k[p](p-\mathbf{h}_k)(p-\mathbf{h}_k)^{\mathrm{T}} \end{aligned} \tag{2.1} hkΣk=pUHk[p]p=pUHk[p](phk)(phk)T(2.1)
其中hk∈R2\mathbf{h}_k \in \mathbb{R}^{2}hkR2表示了第kkk个关键点的置信图的中心坐标,而Σk∈R\Sigma_k \in \mathbb{R}ΣkR则是其方差。U\mathcal{U}U表示了图片坐标的集合,而p∈Up\in\mathcal{U}pU则是遍历了整个置信图。整个过程如Fig 2.4所示,通过式子(2.1),最终需要将置信图更新为以高斯分布表示的形式,如(2.2)所示。
Hk(p)=1αexp⁡(−(p−hk)Σk−1(p−hk))∀p∈U(2.2)H_k(\mathbf{p})=\dfrac{1}{\alpha}\exp(-(\mathbf{p}-\mathbf{h}_k)\Sigma_k^{-1}(\mathbf{p}-\mathbf{h}_k)) \\ \forall p\in\mathcal{U} \tag{2.2} Hk(p)=α1exp((phk)Σk1(phk))pU(2.2)
其中的α\alphaα为标准化系数。最终得到的置信图如Fig 2.4的右下图所示。

gaussian_Hk

confidence_map

Fig 2.4 通过高斯分布拟合,从置信图中计算关键点的中心位置和方差。

至今,我们描述了如何提取关键点,但是这个关键点还没有经过训练,因此其输出还是随机的,不要担心,我们后续会一步步介绍如何进行无监督训练。不过这一章节就此为止吧,为了后续章节的方便,我们先假设我们的 关键点提取是经过训练的,可以提取出较为完美的关键点

稀疏光流图

在引入动作分解的概念之前,我们先花时间去讨论下稀疏光流图。如Fig 3.1所示,假设我们有训练好的关键点检测器,表示为Δ\DeltaΔ,那么输入同一个视频中的不同两帧(我们在后面会解释为什么在训练时候是输入同一个视频的不同两帧),其中用x\mathbf{x}x表示静态图,用x′\mathbf{x}^{\prime}x表示驱动视频(训练时候是和静态图一样,出自同一个视频)中的其中一帧,那么,检测出的关键点可以表示为:
H=Δ(x)H′=Δ(x′)(3.1)\begin{aligned} H &= \Delta(\mathbf{x}) \\ H^{\prime} &= \Delta(\mathbf{x}^{\prime}) \end{aligned} \tag{3.1} HH=Δ(x)=Δ(x)(3.1)
那么,自然地,这两帧之间的对应关键点的相对变化可以简单地用“代数求差”表示,为:
H˙=H′−H(3.2)\dot{H} = H^{\prime}-H \tag{3.2} H˙=HH(3.2)
这里的H˙\dot{H}H˙称之为稀疏光流图,其表示了稀疏关键点在不同帧之间的空间变化,其中每一个关键点的光流表示为hk=[Δx,Δy]h_k = [\Delta x, \Delta y]hk=[Δx,Δy]。可知H˙∈RK×2\dot{H} \in \mathbb{R}^{K \times 2}H˙RK×2,其中KKK是关键点的数量。

kps_detector_more

Fig 3.1 对关键点进行相减,得到稀疏光流图。

但是得到稀疏光流图只能知道关键点是怎么位移形变的,我们该怎么求出关键点周围的像素的位移变化数据呢?

动作分解与泰勒展开

知道了稀疏光流图,我们只知道关键点是怎么变化的,但是对关键点周围的像素的变化却一无所知,我们最终期望的是通过稀疏光流图去推理出密集光流图,如Fig 4.1所示。

dense_motion_network

Fig 4.1 通过稀疏光流图去生成密集光流图。

为了实现这个过程,我们需要引入先验假设,而最为直接的先验假设就是动作分解。

零阶动作分解

一种最简单的动作分解假设就是:

每个关键点周围的主体部件是局部刚性的,因此其位移方向和大小与关键点的相同,我们称之为动作零阶分解。

这个假设通过Fig 4.2可以得到很好地描述,我们通过关键点检测模型可以检测出对应的关键点位移,根据假设,那么周围的身体部分,如橘色点虚线框所示,是呈现刚体变换的,也就是说该区域内的所有和主体有关的部分的像素的位移向量,都和该关键点相同。

locally_rigid

Fig 4.2 关键点周围部件的局部刚体性质:绿色虚线表示的是蓝色关键点周围的主体部件的密集光流,因为假设了关键点周围的刚体性,因此绿色虚线和黄色虚线的大小方向都相同。

那么现在问题就在于,这里谈到的每个关键点的“周围区域”到底有多大,才会使得刚体性质的假设成立。于是问题变成去预测对于每个关节点来说,能使得刚体性质成立的区域了。对于每个关键点,我们通过神经网络预测出一个掩膜Mk∈RH×WM_k \in \mathbb{R}^{H \times W}MkRH×W,那么我们有:
Fcoarse=∑k=1K+1Mk⊗ρ(hk)(4.1)\mathcal{F}_{\mathrm{coarse}} = \sum_{k=1}^{K+1} M_k \otimes \rho(h_k) \tag{4.1} Fcoarse=k=1K+1Mkρ(hk)(4.1)
其中的ρ(⋅)\rho(\cdot)ρ()表示对每个关键点的光流重复H×WH \times WH×W次,得到ρ(⋅)∈RH×W×2\rho(\cdot)\in\mathbb{R}^{H \times W \times 2}ρ()RH×W×2的张量,该过程如Fig 4.3所示,当然这里用箭头的形式表示了光流向量,其实本质上是一个R2\mathbb{R}^2R2的向量;而⊗\otimes表示逐个元素的相乘。

repeat_hw

Fig 4.3 通过在空间上复制每个关键点的光流向量,得到了K个光流图,每个光流图都是单个关键点的简单空间复制。

通常这个掩膜MkM_kMk通过U-net去进行学习得到,这里的U-net也即是Fig 4.1中的Dense Motion Network,用符号MMM表示,其设计的初衷是可以对某个关键点kkk呈现刚体区域进行显著性高亮,如Fig 4.4所示,并且为了考虑相对不变的背景,实际上需要学习出K+1K+1K+1个掩膜,其中一个掩膜用于标识背景,同时也需要ρ([0,0])\rho([0,0])ρ([0,0])用于表示背景区域不曾出现位移。

coarse_flow

Fig 4.4 通过用掩膜去提取出每个关键点的具有局部刚体性质的区域。

除了掩膜之外,模块MMM同样需要预测Fresidual\mathcal{F}_{\mathrm{residual}}Fresidual,作为Fcoarse\mathcal{F}_{\mathrm{coarse}}Fcoarse的补充,其设计的初衷是预测某些非刚体性质的变换,非刚体性质的变换不能通过之前提到的分割主体部分然后进行掩膜的方法得到,因此需要独立出来,通过网络进行预测。于是我们有:
F=Fcoarse+Fresidual(4.2)\mathcal{F} = \mathcal{F}_{\mathrm{coarse}}+\mathcal{F}_{\mathrm{residual}} \tag{4.2} F=Fcoarse+Fresidual(4.2)
现在Dense Motion Network的框图如Fig 4.5所示,我们以上阐述了该模块的输出,现在考虑这个模块的输入。输入主要有稀疏光流图H˙\dot{H}H˙和静态图x\mathbf{x}x,然而在整个优化过程中,由于F\mathcal{F}F其实是和x′\mathbf{x}^{\prime}x对齐的,而输入如果只是x\mathbf{x}x的信息,那么就可能存在优化过程中的困难,因为毕竟存在较大的差别,因此需要显式地先对输入静态图进行一定的变形,可以用双线性采样(Bilinear Sample)[17] 进行,记fw(⋅)f_{w}(\cdot)fw()为双线性采样算符,我们有:
xk=fw(x,ρ(hk))(4.3)\mathbf{x}_k = f_w(\mathbf{x}, \rho(h_k)) \tag{4.3} xk=fw(x,ρ(hk))(4.3)
关于双线性采样的具体细节可见[17],双线性采样可显式地实现图片变形,并且是可微分的,式子(4.3)中的x\mathbf{x}x就是采样输入input,而ρ(hk)\rho(h_k)ρ(hk)就是采样网格grid。其中的xk\mathbf{x}_kxk是根据ρ(hk)\rho(h_k)ρ(hk)只对每个关键点光流进行变形形成的,将H˙\dot{H}H˙{xk}k=1,⋯,K\{\mathbf{x}_k\}_{k=1,\cdots,K}{xk}k=1,,K以及x\mathbf{x}x在通道轴进行拼接,然后作为U-net的输入。

dense_motion_network_Module

Fig 4.5 Dense Motion Network的框图,其输入需要考虑密集光流图的对齐问题。

一阶动作分解

零阶动作分解的假设还是过于简单了,即便是关键点局部区域也不一定呈现出良好的刚体性质,在存在柔性衣物的影响下更是如此,因此引入了一阶动作分解的假设,除了引入的基本假设不同之外,模型其他大部分和零阶动作分解类似。在一阶动作分解下,基本假设变成了

每个关键点周围的主体部件是局部仿射变换[13]的,我们称之为一阶动作分解。

我们接下来会更加形象地用图示解释这个假设,在此之前为了和论文[2]保持一致,先定义一些符号。

我们称静态图为S∈R3×H×W\mathbf{S} \in \mathbb{R}^{3 \times H \times W}SR3×H×W,相当于之前谈到的x\mathbf{x}x;称驱动视频中的某一个驱动帧为D∈R3×H×W\mathbf{D} \in \mathbb{R}^{3 \times H \times W}DR3×H×W,相当于之前谈到的x′\mathbf{x}^{\prime}x。其中密集光流图F∈RH×W×2\mathcal{F} \in \mathbb{R}^{H \times W \times 2}FRH×W×2用一个变换表示,有TS←D:R2→R2\mathcal{T}_{\mathbf{S} \leftarrow \mathbf{D}}:\mathbb{R}^2 \rightarrow \mathbb{R}^2TSD:R2R2,表示从驱动帧到静态图的密集像素位置映射,我们称之为 密集光流映射。和在零阶动作分解章节不同的是,因为驱动帧的主体和静态图的主体可能差别较大(比如人体的衣着方式等),因而导致的不对齐性会影响效果,因此假设存在着一个中间态的抽象参考帧R\mathbf{R}R作为过渡,如Fig 4.6所示,其中我们称在驱动帧里面的点为zk∈R2z_k \in \mathbb{R}^2zkR2,在参考帧的点为pk∈R2p_k \in \mathbb{R}^2pkR2,在静态图的点为wk∈R2w_k \in \mathbb{R}^2wkR2, 不难知道有pk=TR←D(zk)p_k = \mathcal{T}_{\mathbf{R} \leftarrow \mathbf{D}}(z_k)pk=TRD(zk)。那么此时,我们知道密集光流映射可以分解为:
TS←D=TS←R∘TR←D(4.4)\mathcal{T}_{\mathbf{S} \leftarrow \mathbf{D}} = \mathcal{T}_{\mathbf{S} \leftarrow \mathbf{R}} \circ \mathcal{T}_{\mathbf{R} \leftarrow \mathbf{D}} \tag{4.4} TSD=TSRTRD(4.4)
如果假设TR←D\mathcal{T}_{\mathbf{R} \leftarrow \mathbf{D}}TRD在每个关键点局部是双射的,也即是有TR←D=TD←R−1\mathcal{T}_{\mathbf{R} \leftarrow \mathbf{D}} = \mathcal{T}_{\mathbf{D} \leftarrow \mathbf{R}}^{-1}TRD=TDR1,那么此时式子(4.4)变为:
TS←D=TS←R∘TR←D=TS←R∘TD←R−1(4.5)\mathcal{T}_{\mathbf{S} \leftarrow \mathbf{D}} = \mathcal{T}_{\mathbf{S} \leftarrow \mathbf{R}} \circ \mathcal{T}_{\mathbf{R} \leftarrow \mathbf{D}} = \mathcal{T}_{\mathbf{S} \leftarrow \mathbf{R}} \circ \mathcal{T}_{\mathbf{D} \leftarrow \mathbf{R}}^{-1} \tag{4.5} TSD=TSRTRD=TSRTDR1(4.5)
我们发现TS←R,TD←R\mathcal{T}_{\mathbf{S} \leftarrow \mathbf{R}},\mathcal{T}_{\mathbf{D} \leftarrow \mathbf{R}}TSR,TDR都存在一个模式,那就是都是从X←R\mathbf{X} \leftarrow \mathbf{R}XR,因此不妨假设有一个映射TX←R\mathcal{T}_{\mathbf{X} \leftarrow \mathbf{R}}TXR,其中X\mathbf{X}X为任意帧。

ref_domain_to_target

Fig 4.6 将从驱动帧到静态图的映射分解成为了两个阶段,其中通过参考帧作为传递。

精彩的地方来了!因为该映射是一个函数,因此可以通过泰勒函数展开,对于关键点pkp_kpk周围领域ppp进行泰勒展开,有:
TX←R(p)=TX←R(pk)+(ddpTX←R(p)∣p=pk)(p−pk)+o(∣∣p−pk∣∣)(4.6)\mathcal{T}_{\mathbf{X} \leftarrow \mathbf{R}}(p) = \mathcal{T}_{\mathbf{X} \leftarrow \mathbf{R}}(p_k)+(\dfrac{\mathrm{d}}{\mathrm{d}p}\mathcal{T}_{\mathbf{X} \leftarrow \mathbf{R}}(p)\bigg |_{p=p_k})(p-p_k)+o(||p-p_k||) \tag{4.6} TXR(p)=TXR(pk)+(dpdTXR(p)p=pk)(ppk)+o(∣∣ppk∣∣)(4.6)
其中o(∣∣p−pk∣∣)o(||p-p_k||)o(∣∣ppk∣∣)为高阶无穷小项,可以忽略,而(ddpTX←R(p)∣p=pk)(p−pk)(\dfrac{\mathrm{d}}{\mathrm{d}p}\mathcal{T}_{\mathbf{X} \leftarrow \mathbf{R}}(p)\bigg |_{p=p_k})(p-p_k)(dpdTXR(p)p=pk)(ppk)就是一阶近似项,我们通过这个一阶近似项去估计关键点周围领域的变换。从式子(4.6)中我们可以发现,映射TX←R(p)\mathcal{T}_{\mathbf{X} \leftarrow \mathbf{R}}(p)TXR(p)取决于每个关键点以及其对应的Jacobians矩阵[14] 2,有:
TX←R(p)≃{{TX←R(p1),ddpTX←R(p)∣p=p1},⋯,{TX←R(pk),ddpTX←R(p)∣p=pk}}(4.7)\mathcal{T}_{\mathbf{X} \leftarrow \mathbf{R}}(p) \simeq \Bigg \{ \Bigg \{ \mathcal{T}_{\mathbf{X} \leftarrow \mathbf{R}}(p_1),\dfrac{\mathrm{d}}{\mathrm{d}p}\mathcal{T}_{\mathbf{X} \leftarrow \mathbf{R}}(p)\bigg |_{p=p_1} \Bigg\}, \cdots, \\ \Bigg \{ \mathcal{T}_{\mathbf{X} \leftarrow \mathbf{R}}(p_k),\dfrac{\mathrm{d}}{\mathrm{d}p}\mathcal{T}_{\mathbf{X} \leftarrow \mathbf{R}}(p)\bigg |_{p=p_k} \Bigg\} \Bigg\} \tag{4.7} TXR(p){{TXR(p1),dpdTXR(p)p=p1},,{TXR(pk),dpdTXR(p)p=pk}}(4.7)
类似地,对式子(4.5)进行泰勒展开(具体推导见[2]的Sup. Mat.),有:
TS←D(z)≈TS←R(pk)+Jk(z−TD←R(pk))(4.8)\mathcal{T}_{\mathbf{S} \leftarrow \mathbf{D}}(z) \approx \mathcal{T}_{\mathbf{S} \leftarrow \mathbf{R}}(p_k)+J_k(z-\mathcal{T}_{\mathbf{D} \leftarrow \mathbf{R}}(p_k)) \tag{4.8} TSD(z)TSR(pk)+Jk(zTDR(pk))(4.8)
其中:
Jk=(ddpTS←R(p)∣p=pk)(ddpTD←R(p)∣p=pk)−1(4.9)J_k = \Bigg ( \dfrac{\mathrm{d}}{\mathrm{d}p}\mathcal{T}_{\mathbf{S} \leftarrow \mathbf{R}}(p)\bigg |_{p=p_k} \Bigg) \Bigg ( \dfrac{\mathrm{d}}{\mathrm{d}p}\mathcal{T}_{\mathbf{D} \leftarrow \mathbf{R}}(p)\bigg |_{p=p_k} \Bigg)^{-1} \tag{4.9} Jk=(dpdTSR(p)p=pk)(dpdTDR(p)p=pk)1(4.9)
而式子(4.8)中的TS←R(pk),TD←R(pk)\mathcal{T}_{\mathbf{S} \leftarrow \mathbf{R}}(p_k), \mathcal{T}_{\mathbf{D} \leftarrow \mathbf{R}}(p_k)TSR(pk),TDR(pk)实际上关键点的稀疏光流映射,可以用之前在零阶动作分解一章中谈到的无监督关键点提取的方式获得,唯一不同的是,无论是对S\mathbf{S}S还是D\mathbf{D}D的每个关键点 kkk 预测都要附带输出四个通道,这些输出是作为对式子(4.9)中的ddpTS←R(p)∣p=pk\dfrac{\mathrm{d}}{\mathrm{d}p}\mathcal{T}_{\mathbf{S} \leftarrow \mathbf{R}}(p)\bigg |_{p=p_k}dpdTSR(p)p=pkddpTD←R(p)∣p=pk\dfrac{\mathrm{d}}{\mathrm{d}p}\mathcal{T}_{\mathbf{D} \leftarrow \mathbf{R}}(p)\bigg |_{p=p_k}dpdTDR(p)p=pk系数的估计(具体细节还请移步论文[2])。

这个时候的Jk∈R2×2J_k \in \mathbb{R}^{2 \times 2}JkR2×2是该映射的Jacobians矩阵,当Jk=IJ_k = \mathbb{I}Jk=I(其中I\mathbb{I}I为单位矩阵)时,此时退化为零阶动作分解。因为此时显然有:
TS←D(z)≈TS←R(pk)+z−TD←R(pk)=z−(TD←R(pk)−TS←R(pk))=z−(H′−H)=z−H˙(4.10)\begin{aligned} \mathcal{T}_{\mathbf{S} \leftarrow \mathbf{D}}(z) &\approx \mathcal{T}_{\mathbf{S} \leftarrow \mathbf{R}}(p_k)+z-\mathcal{T}_{\mathbf{D} \leftarrow \mathbf{R}}(p_k) \\ &= z-(\mathcal{T}_{\mathbf{D} \leftarrow \mathbf{R}}(p_k)-\mathcal{T}_{\mathbf{S} \leftarrow \mathbf{R}}(p_k)) \\ &= z-(H^{\prime}-H) \\ &= z-\dot{H} \end{aligned} \tag{4.10} TSD(z)TSR(pk)+zTDR(pk)=z(TDR(pk)TSR(pk))=z(HH)=zH˙(4.10)
其中的H˙\dot{H}H˙就是式子(3.2)中提到的稀疏光流图,因此零阶动作分解的实质就是局部刚性变换。

由此,我们可以从几何变换上解释动作的一阶分解,因为z′∈R2×1=z−TD←R(pk)z^{\prime} \in \mathbb{R}^{2 \times 1} = z-\mathcal{T}_{\mathbf{D} \leftarrow \mathbf{R}}(p_k)zR2×1=zTDR(pk)可以视为是关键点pkp_kpk周围领域与关键点之间的位移,这个位移乘上Jacobians矩阵Jk∈R2×2J_k \in \mathbb{R}^{2 \times 2}JkR2×2就是一阶近似项。不妨假设:
Jk=[J11J12J21J22]z′=[z1,z2]T(4.11)\begin{aligned} J_k &= \left[ \begin{matrix} J_{11} & J_{12} \\ J_{21} & J_{22} \end{matrix} \right] \\ z^{\prime} &= [z_{1},z_{2}]^{\mathrm{T}} \end{aligned} \tag{4.11} Jkz=[J11J21J12J22]=[z1,z2]T(4.11)
因此考虑到式子(4.8),有:
z1′=J11z1+J12z2z2′=J21z1+J22z2(4.12)\begin{aligned} z_{1}^{\prime} &= J_{11}z_1+J_{12}z_2 \\ z_{2}^{\prime} &= J_{21}z_1+J_{22}z_2 \end{aligned} \tag{4.12} z1z2=J11z1+J12z2=J21z1+J22z2(4.12)
可以视为是对z′z^{\prime}z的旋转,尺度放缩和切变(不包括平移,因为没有偏移项,具体可见仿射变换具体定义[15]),因此称之为是 (关键点)局部的仿射变换先验假设就是一阶动作分解的本质

那么整理起来,我们的整个框图如Fig 4.7所示,和零阶动作分解框图Fig 4.1不同的是,其预测并且添加了Jacobians矩阵项。

first_order_network

Fig 4.7 引入了一阶动作分解后的框图,大部分组件功能和零阶动作分解框图类似。

当然,同样我们需要通过稀疏光流映射去估计密集光流映射,因此同样会有Dense Motion网络,这个网络和Fig 4.5类似,会去预测出掩膜MkM_kMk,该掩膜的作用和零阶动作分解的作用一致,如Fig 4.4所示。那么有密集光流映射估计T^S←D(z)\mathcal{\hat{T}}_{\mathbf{S} \leftarrow \mathbf{D}}(z)T^SD(z)
T^S←D(z)=M0z+∑k=1KMk(TS←R(pk)+Jk(z−TD←R(pk)))(4.13)\hat{\mathcal{T}}_{\mathbf{S} \leftarrow \mathbf{D}}(z) = M_0z + \sum_{k=1}^{K}M_k (\mathcal{T}_{\mathbf{S} \leftarrow \mathbf{R}}(p_k)+J_k(z-\mathcal{T}_{\mathbf{D} \leftarrow \mathbf{R}}(p_k))) \tag{4.13} T^SD(z)=M0z+k=1KMk(TSR(pk)+Jk(zTDR(pk)))(4.13)
类似地,其中M0M_0M0是对背景的掩膜。具体该网络的输入就不再赘述了,具体见论文[2]。

需要注意的是,在文章[2]中,作者还用Dense Motion网络学习了一个掩膜O^S←D\mathcal{\hat{O}}_{\mathbf{S} \leftarrow \mathbf{D}}O^SD ,该掩膜的作用是去预测被遮挡的部分,该部分不能通过密集光流进行变形得到,需要进行inpainting [16]填充,具体细节不赘述。


总结

在本文,我们通过引入先验,对动作进行分解,可以从稀疏光流图估计出密集光流图,通过将密集光流图输入到变形模型中,可以实现从驱动帧到静态图的转换,这个转换是实现图片动画化的一个重要技术。当然,限于篇幅,还有很多技术点没有谈到,在下个博文,我们将会介绍对应的变形模型,端到端无监督训练模式和该系列模型的缺陷等。一路不易,敬请期待,谢谢支持。


Reference

[1]. Siarohin, A., Lathuilière, S., Tulyakov, S., Ricci, E., & Sebe, N. (2019). Animating arbitrary objects via deep motion transfer. In Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition (pp. 2377-2386).

[2]. Siarohin, A., Lathuilière, S., Tulyakov, S., Ricci, E., & Sebe, N. (2019). First order motion model for image animation. In Advances in Neural Information Processing Systems (pp. 7137-7147).

[3]. https://blog.csdn.net/LoseInVain/article/details/108483736

[4]. Simonyan, K., & Zisserman, A. (2014). Two-stream convolutional networks for action recognition in videos. In Advances in neural information processing systems (pp. 568-576).

[5]. https://en.wikipedia.org/wiki/Optical_flow

[6]. Cao Z , Hidalgo G , Simon T , et al. OpenPose: Realtime Multi-Person 2D Pose Estimation using Part Affinity Fields[J]. IEEE Transactions on Pattern Analysis and Machine Intelligence, PP(99):1-1.

[7]. https://github.com/MVIG-SJTU/AlphaPose

[8]. Bulat, Adrian , and G. Tzimiropoulos . “How Far are We from Solving the 2D & 3D Face Alignment Problem? (and a Dataset of 230,000 3D Facial Landmarks).” IEEE International Conference on Computer Vision IEEE Computer Society, 2017.

[9]. https://github.com/1adrianb/face-alignment

[10]. https://github.com/AliaksandrSiarohin/first-order-model

[11]. Jakab, T., Gupta, A., Bilen, H., & Vedaldi, A. (2018). Unsupervised learning of object landmarks through conditional image generation. In Advances in neural information processing systems (pp. 4016-4027).

[12]. Ronneberger, O., Fischer, P., & Brox, T. (2015, October). U-net: Convolutional networks for biomedical image segmentation. In International Conference on Medical image computing and computer-assisted intervention (pp. 234-241). Springer, Cham.

[13]. https://blog.csdn.net/LoseInVain/article/details/108454304

[14]. https://en.wikipedia.org/wiki/Jacobian_matrix_and_determinant

[15]. https://blog.csdn.net/LoseInVain/article/details/102756630

[16]. https://www.wandb.com/articles/introduction-to-image-inpainting-with-deep-learning

[17]. https://blog.csdn.net/LoseInVain/article/details/108732249


  1. 这里采用高斯分布拟合的目的还有一个就是,在无监督训练开始时,其预测结果是随机的,将其用高斯分布去拟合,才能给后续的优化提供方便。 ↩︎

  2. Jacobians矩阵[14]可以视为是多元函数的导数,在对多元函数进行泰勒展开时候常见。 ↩︎

相关文章:

图片动画化应用中的动作分解方法

作者 | FesianXu 前言 最近基于AI的换脸应用非常的火爆&#xff0c;同时也引起了新一轮的网络伦理大讨论。如果光从技术的角度看&#xff0c;对于视频中的人体动作信息&#xff0c;通常可以通过泰勒展开分解成零阶运动信息与一阶运动信息&#xff0c;如文献[1,2]中提到的&…...

我又和redis超时杠上了

背景 经过上次redis超时排查&#xff0c;并联系云服务商解决之后&#xff0c;redis超时的现象好了一阵子&#xff0c;但是最近又有超时现象报出&#xff0c;但与上次不同的是&#xff0c;这次超时的现象发生在业务高峰期&#xff0c;在简单看过服务器的各项指标以后&#xff0…...

一文带你吃透MySQL数据库!

文章目录1. 索引2. 事务3. 存储引擎4. 锁机制5. MySQL其他知识点文章字数大约1.27万字&#xff0c;阅读大概需要42分钟&#xff0c;建议收藏后慢慢阅读&#xff01;&#xff01;&#xff01;1. 索引 为什么使用索引 通过创建唯一性索引&#xff0c;可以保证数据库表中每一行数据…...

[学习笔记] 2. 数据结构

数据结构视频地址&#xff1a;https://www.bilibili.com/video/BV1uA411N7c5 数据结构是指相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成。简单来说&#xff0c;数据结构就是设计数据以何种方式组织并存储在计算机中。 比如:列表、集合与字…...

[学习笔记] 3. 算法进阶

算法进阶视频地址&#xff1a;https://www.bilibili.com/video/BV1uA411N7c5 1. 贪心算法 贪心算法&#xff08;又称贪婪算法&#xff09;&#xff0c;是指在对问题求解时&#xff0c;总是做出在当前看来是最好的选择。也就是说&#xff0c;不从整体最优上加以考虑 —— 所做…...

做自媒体真的能赚到钱吗?真的能赚到几十万吗?

自媒体在当今社会已经成为一个热门话题&#xff0c;越来越多的人开始尝试做自媒体&#xff0c;希望能够通过自媒体赚到钱。但是&#xff0c;做自媒体真的能赚到钱吗&#xff1f;能赚到几十万吗&#xff1f;下面我们来一一解答。 首先&#xff0c;做自媒体确实可以赚到钱。随着互…...

QT使用QListWidget显示多张图片

Qt系列文章目录 文章目录Qt系列文章目录前言一、QListWidget 和 QListView 的差异二、显示效果1.操作工作区界面1.主界面头文件2. 主界面实现界面2.左边图片目录展示界面1.图片目录头文件2.图片目录实现文件2.属性窗口区1.属性窗口头文件2.属性窗口实现文件3 源码下载前言 QLi…...

python 打印进度条

import time recv_size0 total_size1024while recv_size < total_size:time.sleep(0.1)recv_size1024#打印进度条percentrecv_size / total_sizeres int(50 * percent) * #print(\r[%-50s] %d%% % (res,int(100 * percent)),end) # end 打印以‘’结尾&#xff0c;打印% 需…...

【微小说】大学日记

感谢B站up主“看见晴晴了吗”的视频提供的灵感&#xff0c;链接&#xff1a;https://www.bilibili.com/video/BV1tA411m7Kc 整篇故事完全虚构&#xff0c;如有雷同纯属巧合。 2019年8月25日 星期天 晴 今天是我进入大学的第一天。早晨&#xff0c;我画了美美的妆&#xff0c;穿…...

ArrayList扩容机制解析

1.ArrayList的成员变量 首先我们先了解一下ArrayList的成员变量。 // 默认初始化大小 private static final int DEFAULT_CAPACITY 10;// 空数组&#xff08;用于空实例&#xff09; // 比如List<String> ls new ArrayList<>(0); private static final Object[…...

jsp-----web应用与开发

jsp基本语法 jsp页面的基本结构 定义变量 <%! %> 表达式&#xff1a;变量、常量、表达式 <% %>代码块、程序段【jsp程序代码即jsp脚本】 <% %>注释 隐藏注释 不会显示在客户的浏览器上&#xff0c;即jsp页面运行后页面上看不到注释内容。同时也不会出…...

洛谷 P1201 [USACO1.1]贪婪的送礼者Greedy Gift Givers

题目链接&#xff1a;P1201 [USACO1.1]贪婪的送礼者Greedy Gift Givers - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目描述 对于一群 n 个要互送礼物的朋友&#xff0c;GY 要确定每个人送出的钱比收到的多多少。在这一个问题中&#xff0c;每个人都准备了一些钱来送礼物…...

php设计模式-组合模式的运用

介绍 PHP的组合模式是一种设计模式&#xff0c;用于将对象组合成树形结构以表示“部分-整体”的层次结构。该模式允许客户端统一处理单个对象和组合对象&#xff0c;使得客户端在处理对象时不需要知道对象是否为单个对象还是组合对象。 在组合模式中&#xff0c;有两种类型的…...

一文教会你如何简单使用Fegin进行远程服务调用

文章目录1、fegin的基本介绍2、fegin的基本使用步骤3、项目中的实际运用4、测试前言在分布式微服务中&#xff0c;少不了会进行不同服务之间的相互调用&#xff0c;比如A服务要调用B服务中的接口&#xff0c;如何简单方便的实现呢&#xff1f;fegin可以来帮助。 1、fegin的基本…...

OpenAI——CLIPs(代码使用示例)

OpenAI——CLIPs(打通NLP与CV) Open AI在2021年1月份发布Contrastive Language-Image Pre-training(CLIP),基于对比文本-图像对对比学习的多模态模型&#xff0c;通过图像和它对应的文本描述对比学习&#xff0c;模型能够学习到文本-图像对的匹配关系。它开源、多模态、zero-s…...

什么样的人更适合创业?那类人创业更容易成功?

创业是一项充满风险和机遇的事业&#xff0c;成功的创业者需要具备一定的素质和能力。那么&#xff0c;什么样的人更适合创业&#xff1f;哪类人创业更容易成功呢&#xff1f;本文将为您介绍几个适合创业的人群和成功创业者的共同特点。 具有创新精神的人 创业需要不断创新&am…...

JavaApi操作ElasticSearch(强烈推荐)

ElasticSearch 高级 1 javaApi操作es环境搭建 在elasticsearch官网中提供了各种语言的客户端&#xff1a;https://www.elastic.co/guide/en/elasticsearch/client/index.html 而Java的客户端就有两个&#xff1a; 不过Java API这个客户端&#xff08;Transport Client&#…...

NFT的前景,元宇宙的发展

互联网的普及和数字技术的广泛应用&#xff0c;成为消费升级的新动力&#xff0c;在不断创造出更好的数字化生活的同时&#xff0c;也改变了人们的消费习惯、消费内容、消费模式&#xff0c;甚至是消费理念&#xff0c;数字经济时代的文化消费呈现出新的特征。 2020年有关机构工…...

C#基础教程20 预处理器指令

文章目录 C#预处理指令教程简介预处理指令格式指令名 参数预处理指令类型条件编译指令if#if 条件表达式宏定义指令总结C#预处理指令教程 简介 预处理指令是在编译代码之前进行的一种处理,可以让程序员在编译前根据需要对代码进行一些修改、调整或者控制。C#语言中的预处理指令…...

【FPGA】Verilog:时序电路设计 | 二进制计数器 | 计数器 | 分频器 | 时序约束

前言&#xff1a;本章内容主要是演示Vivado下利用Verilog语言进行电路设计、仿真、综合和下载 示例&#xff1a;计数器与分频器 ​​ 功能特性&#xff1a; 采用 Xilinx Artix-7 XC7A35T芯片 配置方式&#xff1a;USB-JTAG/SPI Flash 高达100MHz 的内部时钟速度 存储器&#…...

国外SEO策略指南:确保你的网站排名第一!

如果你想在谷歌等搜索引擎中获得更高的排名并吸引更多的流量和潜在客户&#xff0c;那么你需要了解一些国外SEO策略。 下面是一些可以帮助你提高谷歌排名的关键策略。 网站结构和内容优化 谷歌的搜索算法会考虑网站的结构和内容。 因此&#xff0c;你需要优化网站结构&…...

Tik Tok新手秘籍,做好五点可轻松起号

新手做TikTok需要有一个具体的规划布局&#xff0c;如果没有深思熟虑就上手开始的话&#xff0c;很有可能会导致功亏一篑&#xff0c;甚至是浪费时间。因此&#xff0c;想要做好 TikTok&#xff0c;就必须从最基本的运营细节开始&#xff0c;一步一步来&#xff0c;下面为大家分…...

【Linux】网络入门

&#x1f387;Linux&#xff1a; 博客主页&#xff1a;一起去看日落吗分享博主的在Linux中学习到的知识和遇到的问题博主的能力有限&#xff0c;出现错误希望大家不吝赐教分享给大家一句我很喜欢的话&#xff1a; 看似不起波澜的日复一日&#xff0c;一定会在某一天让你看见坚持…...

回溯法——力扣题型全解【更新中】

&#xff08;本文源自网上教程的笔记&#xff09; 回溯基础理论 回溯搜索法&#xff0c;它是一种搜索的方式。 回溯是递归的副产品&#xff0c;只要有递归就会有回溯。 所以以下讲解中&#xff0c;回溯函数也就是递归函数&#xff0c;指的都是一个函数。 回溯法的效率 虽然…...

【华为机试真题详解 Python实现】分奖金【2023 Q1 | 100分】

文章目录 前言题目描述输入描述输出描述示例 1题目解析参考代码前言 《华为机试真题详解》专栏含牛客网华为专栏、华为面经试题、华为OD机试真题。 如果您在准备华为的面试,期间有想了解的可以私信我,我会尽可能帮您解答,也可以给您一些建议! 本文解法非最优解(即非性能…...

netlink进行网卡重命名

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <sys/socket.h> #include <linux/if.h> #include <linux/netlink.h>#define MAX_PAYLOAD 1024 // 最大负载长…...

2023年春【数据分析与挖掘】文献精读(一)-1:针对COVID-19,使用聚类方法有效提取生物特性关联进而识别预防COVID-19的药物

分享给大家——动漫《画江湖之不良人》第四季片尾,主人公 李星云所说的一段话: 悠悠众生,因果循环,大道至简,世间若尽是不如意事, 越是执着,便越是苦,不如安下心来,看该看的风景,做好该做之事。 初行娆疆,所悟如此, 就像曾经有一位紫衣姑娘,第一次来中原时,一样…...

【Go自学第三节】Go的范围(Range)用法

Go 语言中 range 关键字用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。在数组和切片中它返回元素的索引和索引对应的值&#xff0c;在集合中返回 key-value 对。 在讲Go语言的range之前&#xff0c;我们先回顾下Python中range的用法 for i …...

【备战面试】每日10道面试题打卡-Day6

本篇总结的是计算机网络知识相关的面试题&#xff0c;后续也会更新其他相关内容 文章目录1、HTTP 与 HTTPS 有哪些区别&#xff1f;2、HTTPS的加密过程是什么&#xff1f;3、GET与POST有什么区别&#xff1f;4、讲讲HTTP各个版本的区别&#xff1f;5、HTTP与FTP的区别&#xff…...

Stable Diffusion 个人推荐的各种模型及设置参数、扩展应用等合集(不断更新中)

一、说明 | 表示或者 表示 以上 二、模型 适用风景、房子、车子等漫画类风格 模型的VAE不要用模型附带的&#xff0c;好像就是naifu的官方vae&#xff0c;很老了&#xff0c;用 vae-ft-mse-840000-ema-pruned.ckpt 或者是 kl-f8-anime2.ckpt&#xff1b; 嵌入模型要下载作者…...

Salesforce 2023财年逆风增长,现金流达历史最高!

在过去的一年里&#xff0c;Salesforce一直是华尔街最关注的公司之一。3月1日&#xff0c;CRM领域的全球领导者Salesforce公布了截至2023年1月31日的第四季度和整个财年的业绩。 Salesforce主席兼首席执行官Marc Benioff表示&#xff1a; Salesforce全年实现了314亿美元的收入…...

2023年3月全国数据治理工程师认证DAMA-CDGA/CDGP考试怎么通过?

弘博创新是DAMA中国授权的数据治理人才培养基地&#xff0c;贴合市场需求定制教学体系&#xff0c;采用行业资深名师授课&#xff0c;理论与实践案例相结合&#xff0c;快速全面提升个人/企业数据治理专业知识与实践经验&#xff0c;通过考试还能获得数据专业领域证书。 DAMA认…...

【安卓软件】KMPlayer-一款完美的媒体播放器 可以播放所有格式的字幕和视频

KM PlayerKM Player是一款未编码的视频播放器&#xff0c;让您无需编码即可方便地播放各种格式的视频&#xff0c;并为您的新体验添加了字幕支持、视频播放速度和手势等功能。KMPlayer 拥有美观和直观的设计&#xff0c;让您可以更方便地管理和播放视频&#xff01;功能高品质视…...

ClickHouse--分布式查询多副本的路由规则

前言在集群情况下&#xff0c;数据写入可以有写本地表和写分布式表2种方案&#xff0c;但是面向集群查询时&#xff0c;只能通过Distributed表引擎实现。本文主要介绍分布式查询多副本的路由规则。该配置项为&#xff1a;load_balancerandom/nearest_hostname/in_order/first_o…...

Linux 常用命令总结

本篇博客记录读研以来高频使用的 linux 系统下的命令合集 命令分类程序运行系统相关文件处理文件传输相关命令文件显示相关命令文件排列相关命令Anaconda 相关命令tmux 终端复用神器使用tips程序运行 自动保存日志&#xff0c;替代write命令&#xff1a; xxx | tee ./xxx.log…...

超分扩散模型 SR3 可以做图像去雨、去雾等恢复任务吗?

文章目录前言代码及原文链接主要的点如何进行图像恢复前言 关于扩散模型以及条件扩散模型的介绍&#xff0c;大家可以前往我的上一篇博客&#xff1a;扩散模型diffusion model用于图像恢复任务详细原理 (去雨&#xff0c;去雾等皆可)&#xff0c;附实现代码。 SR3是利用扩散模…...

STM32Cube STM32MP157 M4端CAN通讯实战

1、环境 开发系列&#xff1a;STM32MP157 开发软件&#xff1a;STM32CubeIDE 1.4.0 例程目的&#xff1a;在M4端实现CAN通讯 2、目的 近日&#xff0c;有客户需要在STM32MP157中的M4端实现CAN通讯&#xff0c;我也是初次在M4端编写CAN通讯代码&#xff0c;上网研究了其他人写…...

npm install报错unable to resolve dependency tree

一、问题背景npm install安装项目依赖时报错PS D:\test> npm install npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! npm ERR! While resolving: vue-admin-template4.2.1 npm ERR! Found: webpack5.74.0 npm ERR! node_modules/we…...

力扣sql简单篇练习(二十六)

力扣sql简单篇练习(二十六) 1 每家商店的产品价格 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # 多行变成多列,考虑用sum if分组 SELECT product_id,sum(IF(storestore1,price,null)) store1,sum(IF(storestore2,price,null)) store2, sum(IF(st…...

2022年全国职业院校技能大赛(中职组)网络安全竞赛试题A模块第九套解析(详细)

2022年全国职业院校技能大赛(中职组) 网络安全竞赛试题 (9) (总分100分) 赛题说明 一、竞赛项目简介 “网络安全”竞赛共分A.基础设施设置与安全加固;B.网络安全事件响应、数字取证调查和应用安全;C.CTF夺旗-攻击;D.CTF夺旗-防御等四个模块。根据比赛实际情况,竞…...

C++回顾(十六)—— 异常处理机制

16.1 异常的基本语法 1&#xff09; 若有异常则通过throw操作创建一个异常对象并抛掷。2&#xff09; 将可能抛出异常的程序段嵌在try块之中。控制通过正常的顺序执行到达try语句&#xff0c;然后执行try块内的保护段。3&#xff09; 如果在保护段执行期间没有引起异常&#xf…...

【100个 Unity实用技能】 | Unity 在代码中 动态改变RectTransform位置及宽高 的方法整理

Unity 小科普 老规矩&#xff0c;先介绍一下 Unity 的科普小知识&#xff1a; Unity是 实时3D互动内容创作和运营平台 。包括游戏开发、美术、建筑、汽车设计、影视在内的所有创作者&#xff0c;借助 Unity 将创意变成现实。Unity 平台提供一整套完善的软件解决方案&#xff…...

哈希表的实现

哈希表概念 二叉搜索树具有对数时间的表现&#xff0c;但这样的表现建立在一个假设上&#xff1a;输入的数据有足够的随机性。哈希表又名散列表&#xff0c;在插入、删除、搜索等操作上具有「常数平均时间」的表现&#xff0c;而且这种表现是以统计为基础&#xff0c;不需依赖…...

搞懂海明码

海明码搞懂之前先了解奇偶校验。例如&#xff1a;1111 对其进行奇偶校验。 奇检验&#xff1a;11111 奇校验使1的个数保持在奇数 偶校验&#xff1a;01111 偶校验使1的个数保持在偶数 海明码可以拆分为三步&#xff1a; 一、确定校验的位数 公式&#xff1a;2^k > k n …...

数据库:Mysql数据库安装及使用

目录 一、数据库介绍 1、基本概念 2、数据库类型 3、版本演变 二、Mysql安装 1、官网下载yum安装 2、手动配置yum安装 三、Mysql基本操作 1、登录与改密 2、检测数据库健康 3、 库的创建与使用 4、数据类型 5、修饰符 6、表的创建与使用 7、分组查询 8、查询排…...

【冲刺蓝桥杯的最后30天】day7

大家好&#x1f603;&#xff0c;我是想要慢慢变得优秀的向阳&#x1f31e;同学&#x1f468;‍&#x1f4bb;&#xff0c;断更了整整一年&#xff0c;又开始恢复CSDN更新&#xff0c;从今天开始更新备战蓝桥30天系列&#xff0c;一共30天&#xff0c;如果对你有帮助或者正在备…...

REG.EXE修改注册表-解决win10微软输入法默认中文,将其全局修改为英文

REG.EXE修改注册表-解决win10微软输入法默认中文&#xff0c;将其全局修改为英文 使用REG.EXE 可以直接强制修改注册表字段 修改注册表&#xff1a; REG.EXE ADD 注册表路径 /v 注册表项字段 /t 注册表字段类型 /d 注册表值 /f 例如&#xff1a; REG. EX ADD HKLM\System\C…...

hive之正则函数研究学习regex/regex_replace/regex_extract

首先学习这个之前要先知道一些正则的基本知识。 随便百度一下正则表达式 – 元字符 | 菜鸟教程 字符描述\ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用、或一个八进制转义符。例如&#xff0c;n 匹配字符 "n"。\n 匹配一个换行符。序列 \\ 匹…...

Codeforces Round 854 by cybercats (Div. 1 + Div. 2) C、D1

C. Double Lexicographically Minimum 题意 字符串sss&#xff0c;你可以把它按任意顺序组合&#xff0c;保留的是你组合的字符串和它的倒序之间大的那一个&#xff0c;问你在满足上面条件的前提下字典序最小的字符串。 思路 分析不难发现在没达到一个关键的点的时候肯定是…...

API 网关日志的价值,你了解多少?

本文介绍了 API 网关日志的价值&#xff0c;并以知名网关 Apache APISIX 为例&#xff0c;展示如何集成 API 网关日志。 作者钱勇&#xff0c;API7.ai 技术工程师&#xff0c;Apache APISIX Committer。 原文链接 网关日志的价值 在数字化时代&#xff0c;软件架构随着业务成…...