UE4产生的motion vector是后向运动矢量,具体来说,第 i i i帧的运动矢量 M V i MV_i MVi表示第 i i i帧(当前帧)到第 i − 1 i-1 i−1帧(前一帧)的运动关系,换句话说,对于像素 p p p, M V i [ p ] = π i → i − 1 ( p ) MV_i[p]=\pi_{i\rightarrow i-1}(p) MVi[p]=πi→i−1(p),其中 π i → i − 1 ( p ) \pi_{i\rightarrow i-1}(p) πi→i−1(p)表示像素 p p p从当前帧 i i i位置到前一帧 i − 1 i-1 i−1的运动变换值。
使用产生的后向运动矢量,分别给出帧 i − 1 → i i-1\rightarrow i i−1→i的图像扭曲(forwardWarping()
),与帧 i → i − 1 i\rightarrow i-1 i→i−1的图像扭曲(backwardWarping()
),其中后者写法并不优美,进行了一定的舍入而造成像素错位。
还有就是numpy与UE4产生/处理图像时均以从左向右为y轴(图宽width);而原点方面,UE4在图像左下角,numpy在图像左上角,因此UE4以从下到上为x轴(图长height),而numpy则是从上到下,所以在计算时需要注意x坐标的正负转化。
import cv2 as cv
import numpy as np
def forwardWarping(img,mv):#img[i-1],mv[i]->img[i]
h,w,c= img.shape
ch=np.arange(0,h*w).reshape(h,w)//w+mv[...,0]
cw=np.arange(0,h*w).reshape(h,w)%w-mv[...,1]
ch=ch.astype(np.float32)
cw=cw.astype(np.float32)
res=cv.remap(img,cw,ch,cv.INTER_LINEAR)
return res
def backWarping(img,mv,depth):#img[i],mv[i],depth[i]->img[i-1]
h,w,c=img.shape
res=np.zeros_like(img)
mv_oneaxis=mv.reshape(-1,2)
I=np.arange(0,h*w)//w
J=np.arange(0,h*w)%w
#很粗的写法,直接进行四舍五入,会造成微小的错位
II=(I+mv_oneaxis[:,0]+0.5).clip(0,h)
JJ=(J-mv_oneaxis[:,1]+0.5).clip(0,w)
II=II.astype(np.int32)
JJ=JJ.astype(np.int32)
id=np.argsort(-depth.reshape(-1))#考虑深度测试,当后一帧有多个位置映射到前一帧的相同位置时,选择最靠近相机(深度最小)的那个
res[II[id],JJ[id]]=img[I[id],J[id]]
return res