Here is a Python solution to warp image from optical flow:
import cv2
import numpy as np
def warp_flow(flow, img1=None, img2=None, interpolation=cv2.INTER_LINEAR):
"""Use remap to warp flow, generating a new image.
Args:
flow (np.ndarray): flow
img1 (np.ndarray, optional): previous frame
img2 (np.ndarray, optional): next frame
Returns:
warped image
If img1 is input, the output will be img2_warped, but there will be multiple pixels corresponding to a single pixel, resulting in sparse holes.
If img2 is input, the output will be img1_warped, and there will be no sparse holes. The latter approach is preferred.
"""
h, w, _ = flow.shape
remap_flow = flow.transpose(2, 0, 1)
remap_xy = np.float32(np.mgrid[:h, :w][::-1])
if img1 is not None:
uv_new = (remap_xy + remap_flow).round().astype(np.int32)
mask = (uv_new[0] >= 0) & (uv_new[1] >= 0) & (uv_new[0] < w) & (uv_new[1] < h)
uv_new_ = uv_new[:, mask]
remap_xy[:, uv_new_[1], uv_new_[0]] = remap_xy[:, mask]
remap_x, remap_y = remap_xy
img2_warped = cv2.remap(img1, remap_x, remap_y, interpolation)
mask_remaped = np.zeros((h, w), np.bool8)
mask_remaped[uv_new_[1], uv_new_[0]] = True
img2_warped[~mask_remaped] = 0
return img2_warped
elif img2 is not None:
remap_x, remap_y = np.float32(remap_xy + remap_flow)
return cv2.remap(img2, remap_x, remap_y, interpolation)
img1 = cv2.imread("img1.jpg")
img2 = cv2.imread("img2.jpg")
flow = cv2.calcOpticalFlowFarneback(
img1.mean(-1), img2.mean(-1), None, 0.5, 3, 15, 3, 5, 1.2, 0
)
img2_warped = warp_flow(flow, img1=img1)
img1_warped = warp_flow(flow, img2=img2)
cv2.imwrite("warped.jpg", np.vstack([img1_warped, img2_warped]))
cv2.imwrite("target.jpg", np.vstack([img1, img2]))
The examples img1
, img2
and flow visualization :

The results, left: warped.jpg
,right: target.jpg
:
