计算机生成的虚拟背景使得各类演播室场景可通过非常经济的手段实现,不仅提高了节目制作效率和演播室利用率,同时也摆脱了物理上空间、时间及道具的限制,为节目创作提供了无限想象和表现空间。但对大多数电视台而言,三维图形实时计算的成本太高,事实上新闻访谈等节目中,三维虚拟演播室中高成本的功能很少使用。在功能和成本间平衡,实用、简单,图像质量高的二维虚拟演播室,或虚拟背景系统极具吸引力。
二维虚拟演播室由传统色键演变而来,但突破了前景和背景只是简单迭加,无法完美融合的限制。与三维不同在于摄像机运动参数控制下的场景变换不是基于实时三维图形计算,而是基于图像变换。例如,当摄像机拉近、推后前景时,在摄像机运动参数控制下,产生一个放大、缩小的虚拟背景图像与前景变化实时匹配合成。
二维虚拟演播室涉及数字视频图像的各种实时变换计算。本文将讨论典型的图像缩放运算在虚拟背景系统中的实现策略:简单地使用Y=rX的线性比例方式进行图像线性缩放,图像显示质量不够理想,原因在于数字视频图像离散单点采样的信息丢失引起的失真。本文将平衡考虑质量和速度因素,具体讨论基于邻近四点采样和插值的双线性插值算法及其优化实现。
双线性插值的基本思想
假定待显示图像D的分辨率为W×H,源图像S的分辨率为U×V。对于D中任意一象素点p(x,y),0≤x≤W-1,0≤y≤H-1,通过纵横缩放比例因子r1、r2和线性对应关系,可求得p点在S中的逻辑对应点P(u,v)的u,v坐标值(采用从显示图像象素到源图像象素的逆运算,是为了避免正向计算时由于离散化采样造成的显示图像黑洞)。即
如图1所示,P0、P1、P2、P3是源图像S中离逻辑P(u,v)点最近的四个物理象素点。通过u、v的截断取整[u]、[v],不难得到P0、P1、P2、P3在S中的坐标分别为P0([u],[v])、P1([u+1],[v])、P2([u],[v+1])、P3 ([u+1],[v+1])。u、v的小数部分分别记为t、s,有
t=u-[u] 0.0≤t≤1.0; s=v-[v] 0.0≤s≤1.0 (2)
显见,t、s、1-t、1-s分别为P垂直、水平到P0、P1、P2、P3的距离。这些距离同时也是计算P点加权平均值所引用各点的权重因子,原则上权重与到P点的距离成反比关系。
假定象素值为有arpha通道32位颜色数,P、P0、P1、P2、P3点的象素值分别为(R,G,B,A)、(R0,G0,B0,A0)、(R1,G1,B1,A1)、(R2,G2,B2,A2)、(R3,G3,B3,A3),则有:
该方法虽改进了缩放质量,满足了显示需求,但也显著增加了计算量,引发了新的实时性问题。实验表明,即使使用Intel体系(IA)汇编代码直接实现,也无法满足每秒生成25帧显示图像的需求。同时其浮点计算要求使得无法单独采用MMX加速。因此考虑使用SIMD扩展指令为主的优化。
IA体系基础上扩展的SIMD模型简介
流化SIMD扩展子集建立在IA体系之上,并与原有体系保持全兼容。扩展包括8个新的SIMD浮点寄存器(XMM0到XMM7),SIMD浮点数据类型(128位成组浮点数据)和增强的流化SIMD指令子集,籍此引入了新的操作系统可见状态。它通过定义一个简单灵活的软件模型提高并行计算程度。一条单独指令并行处理多个数据元素的SIMD执行模型使得CPU能够支持在成组单精度浮点数据类型上的算术或逻辑并行操作,附加的SIMD整数指令能够支持在成组字节、字、双字数据类型上的并行操作。
1. SIMD浮点寄存器
8个128位SIMD浮点寄存器都可通过寄存器名字(XMM0到XMM7)被直接寻址定位,它们用于加载128位成组数据,并对其执行计算。128位分别标号为0到127,位0为LSB最低有效位,位127是MSB最高有效。寄存器有两种数据存取模式,128位存取和32位存取模式。这些浮点寄存器不能用于内存寻址,内存寻址必须使用整数寄存器(EAX、EBX、ECX、EDX、EBP、ESI、EDI、ESP)和标准的IA寻址模式。
此外,引入一个新的MXCSR控制、状态寄存器,用于数字的异常处理,或设置取整模式、观察状态标志等。
MMX寄存器实际上是IA体系中普通浮点寄存器的映像,因此从MMX操作转换到浮点操作需要执行EMMS指令进行切换。与MMX不同,SIMD浮点寄存器是单独的寄存器空间,因此SIMD扩展指令可以与MMX指令或者浮点指令之一混合使用,不用执行EMMS指令切换。 2. SIMD浮点数据类型
SIMD寄存器操作的主要数据类型是成组单精度浮点操作数,是包含在128位成组数据类型中的四个32位的单精度浮点数字,标号从0到3,标号0的数保存在寄存器的最低32位。该类型的16个字节在内存中按照小尾模式占用连续地址。新的SIMD整数指令以成组字节、字或者双字数据类型为操作单元。SIMD以64位或128位的块为单位从内存中一次性读/写成组的数据类型,新的预取指令则工作在大小至少为32字节的无类型数据上。但是,当在成组数据类型上执行算术、逻辑运算时,则按照单指令、多数据执行模型,对SIMD浮点寄存器中包含的独立单精度浮点操作数进行并行运算。新的SIMD整数指令沿用MMX的指令约定,并且是操纵MMX寄存器中的数据,并不操纵SIMD128位浮点寄存器。
3. SIMD扩展指令集
SIMD扩展指令集共包含70条指令,分为数据移动指令、算术运算指令、比较指令、变换指令、逻辑运算指令、附加的SIMD整数指令、移位指令、状态管理指令、高速缓存控制指令等9类。
在SIMD扩展中,除了显式说明不需对齐的装入和存储指令外,其它所有SIMD指令涉及的内存操作数的地址必须按照16字节长度单位对齐地址边界,否则会引起执行保护错误。这或许与处理器的高速预取缓存按16字节的边界提取有关。
SIMD指令有两种操作模式,分别是成组模式和标量模式。成组模式如图2a所示,并行对两个操作数中的XI与YI字段执行运算;标量模式如图2b所示,仅对两个操作数的一对最低有效字段X4、Y4执行运算,运算过程中,第一个操作数的前三个单精度浮点数被直接送到目的地。
a. 相关SIMD指令
MOVUPS 用于将128位数据从内存传输到SIMD浮点寄存器,或者从SIMD浮点寄存器传输到内存,也可在SIMD浮点寄存器之间传输,对128位数据的对齐方式没有任何限制。
SHUFPS 指令用于将四个成组单精度浮点数从源操作数成组移位到目标寄存器的低两位字段;目标寄存器的高两位字段则通过目标寄存器中的四个单精度浮点数字以相同方式成组移位产生。
CVTTPS2PI 用于将两个低位单精度浮点数截去小数点后数字,变成两个32位有符号整数,存入某个MMX寄存器中。
CVTPI2PS 用于将64位MMX寄存器中的两个32位有符号整数转换为两个32位单精度浮点数,存入某个SIMD寄存器的低两位,两个高位不变。
CVTPS2PI 用于将SIMD寄存器中两个低位单精度浮点转换为两个32位有符号整数,存入某个64位MMX寄存器。按照MXCSR寄存器中的舍入模式取整。
ADDPS 用于对源和目标操作数中的四对单精度浮点数执行并行成组加法,并将结果存入目标操作数。
SUBPS 用于对源和目标操作数中的四对单精度浮点数执行并行成组减法,并将结果存入目标操作数。
MULPS 用于对源和目标操作数中的四对单精度浮点数执行并行成组乘法,并将结果存入目标操作数。
b. MMX相关指令
PUNPCKLBW 用于将源操作数的四个低位字节和目标操作数的四个低位字节交替取出并写入到MMX寄存器中。
PUNPCKHWD 用于将源操作数的两个高位字和目标操作数的两个高位字交替取出,并写入到MMX寄存器中。
PUNPCKLWD 指令用于将源操作数的两个低位字和目标操作数的两个低位字交替取出,并写入到MMX寄存器中。
PACKSSDW 指令将两个有符号双字组的源操作数和两个有符号双字组的目标操作数变成四个有符号的字组,并存入目标寄存器中。如果有符号双字的值超出有符号字的取值范围,采用饱和方式处理。 PACKUSWB 指令将四个有符号字的源操作数和四个有符号字的目标操作数按饱和方式处理成八个字节组,并将结果存入目标操作数。
基于SIMD的优化实现
1. 算法优化
在计算P点的R、G、B、A值前,将公式3、4、5和6首先改写为与各点权重因子相乘的方式。
2. 关键步骤
简化起见,下面仅分析、讨论代码实现中几个关键步骤,完整代码略。
a. CPU检测
首先使用CPUID指令确认CPU是否支持SIMD扩展。要正常使用SIMD扩展,EDX寄存器中返回的特征标志位必须同时满足:第2位为0,意指禁止浮点指令仿真;第9位为1,意指操作系统在多任务上下文切换时能感知并支持保存SIMD寄存器状态;第25位为1,意指CPU支持SIMD扩展。
b. 距离t、s成组计算
为了并行计算象素P(u,v)的RGBA值,u、v的小数部分t、s必须成组存放到XMM浮点寄存器中。结合图例3a中t的计算,说明如何从u、v中分离、成组获取t、s值以便后面计算权重因子。
通过movups指令将由P(x,y)计算得到的u、v浮点数装入一个xmm寄存器;使用cvtps2pi指令将u、v的整数部分[u]、[v]暂时存入一个64位的MMX寄存器中;利用cvtpi2ps指令再次将MMX寄存器中的[u]、[v]转换为32位单精度浮点形式存入另一xmm寄存器;利用shufps移位指令将四个32位浮点一组的u、v值和[u]、[v]值对齐;利用subps成组减法指令得到存储在xmm寄存器中四个一组的t、s浮点数值。
在此基础上可进一步计算出成组的1-t和1-s浮点值。
c. 象素RGBA值从字节到浮点
虽然源和显示图像的象素值均为4个单字节的整数,但加权平均求和是一个浮点计算过程,因此在并行计算P(x、y)(也就是P(u、v))点的R、G、B、A值前,需要将临近点P0、P1、P2、P3的象素值分量从字节整数转换为浮点数。以P0为例,结合图3b,假定R0、G0、B0、A0已用SIMD整数指令按成组字节方式装入MMX寄存器的低端:
使用punpcklbw MMX指令将MMX寄存器低端四个成组字节整数转换为四个16位成组字整数,存入MMX寄存器中;
分别使用punpckhwd和punpcklwd MMX指令将四个16位成组字整数变为两组双字整数,每组包含两个32位双字整数,分别存入两个MMX寄存器;
使用cvtpi2ps指令将两个MMX寄存器中的成组双字整数变为32位浮点数,并分别存入两个xmm寄存器的低端;
使用shufps指令将两个xmm寄存器低端64位中的两个浮点数组合到一个xmm寄存器中,最终得到R0、G0、B0、A0分量的成组浮点形式fR0、fG0、fB0、fA0。
d. 源象素点加权并行计算 以临近点P3为例,结合图3c,说明相邻点对P(u、v)象素值的贡献如何并行计算。
e. 目标点象素值加权求和并行计算和字节表示
如图3d所示,分两步将P0、P1、P2、P3点对P点各分量的贡献用三次addps成组加法指令加起来,就得到了P点RGBA的浮点表示fR、fG、fB、fA。在填充到视频缓冲区之前,需要将结果变回字节形式。将浮点形式的fR、fG、fB、fA变回字节整数R、G、B、A的过程是图3b的逆过程,不再讨论。
存取优化
除了并行计算外,通过仔细安排存取代码也可获得SIMD在内存存取等待上的性能改善。
(全文信息请参考:)
作者:王炜 武德峰
r1=U/W; r2=V/H; u=r1×x, 0≤u≤U-1; v=r2×y, 0≤v≤V-1 (1)
R=(1.0-s)×[(1.0-t)×R0+t×R1]+s×[(1.0-t)×R2+t×R3] (3)
G=(1.0-s)×[(1.0-t)×G0+t×G1]+s×[(1.0-t)×G2+t×G3] (4)
B=(1.0-s)×[(1.0-t)×B0+t×B1]+s×[(1.0-t)×B2+t×B3] (5)
A=(1.0-s)×[(1.0-t)×A0+t×A1]+s×[(1.0-t)×A2+t×A3] (6)
R=uv0×R0+uv1×R1+uv2×R2+uv3×R3
G=uv0×G0+uv1×G1+uv2×G2+uv3×G3
B=uv0×B0+uv1×B1+uv2×B2+uv3×B3
A=uv0×A0+uv1×A1+uv2×A2+uv3×A3
uv0 =(1.0-s)×(1.0-t)
uv1 =(1.0-s)×t
uv2 =(1.0-t)×s
uv3 =t×s
其中uv0、uv1、uv2、uv3分别为P0、P1、P2、P3的权重因子,预先准备显然减少了浮点乘法,提高了整体性能。
使用mulps指令将xmm中的成组s和t进行并行乘法运算,得到成组的P3点权重因子uv3。
使用mulps指令将xmm中的成组的uv3和fR3、fG3、fB3、fA3进行并行乘法,得到P3对P点各分量的贡献。
类似可以计算uv0、uv1、uv2和P0、P1、P2点对P点各分量的贡献。
国防科技大学5院管理科学与工程系
Email: Soul_eudemon@