光流是预测两个图像之间运动的任务,通常是视频的两个连续帧。光流模型以两张图像作为输入,并预测一个流:流表示第一张图像中每一个像素的位移,并将其映射到第二张图像中对应的像素。流是(2,H, W)维张量,其中第一个轴对应于预测的水平和垂直位移。
下面的例子说明了如何使用我们实现的RAFT模型来预测流量。我们还将看到如何将预测的流转换为RGB图像以进行可视化。
import numpy as np
import torch
import matplotlib.pyplot as plt
import torchvision.transforms.functional as F
plt.rcParams["savefig.bbox"] = "tight"
def plot(imgs, **imshow_kwargs):
if not isinstance(imgs[0], list):
# Make a 2d grid even if there's just 1 row
imgs = [imgs]
num_rows = len(imgs)
num_cols = len(imgs[0])
_, axs = plt.subplots(nrows=num_rows, ncols=num_cols, squeeze=False)
for row_idx, row in enumerate(imgs):
for col_idx, img in enumerate(row):
ax = axs[row_idx, col_idx]
img = F.to_pil_image(img.to("cpu"))
ax.imshow(np.asarray(img), **imshow_kwargs)
ax.set(xticklabels=[], yticklabels=[], xticks=[], yticks=[])
plt.tight_layout()
使用Torchvision读取视频
我们将首先使用read_video()
读取一个视频。或者也可以使用新的VideoReader
API(如果torchvision是从源代码构建的)。我们在这里使用的视频来自pexels.com,免费使用,感谢Pavel Danilyuk。
import tempfile
from pathlib import Path
from urllib.request import urlretrieve
video_url = "https://download.pytorch.org/tutorial/pexelscom_pavel_danilyuk_basketball_hd.mp4"
video_path = Path(tempfile.mkdtemp()) / "basketball.mp4"
_ = urlretrieve(video_url, video_path)
Read_video()
返回视频帧、音频帧和与视频相关的元数据。在我们的例子中,我们只需要视频帧。
这里我们只会在2对预选的帧之间进行2次预测,即帧(100,101)和帧(150,151)。这些对中的每一对都对应一个单一的模型输入。
from torchvision.io import read_video
frames, _, _ = read_video(str(video_path))
# THWC-> TCHW
frames = frames.permute(0, 3, 1, 2)
img1_batch = torch.stack([frames[100], frames[150]])
img2_batch = torch.stack([frames[101], frames[151]])
plot(img1_batch)
RAFT模型接受RGB图像。我们首先从read_video()
中获取帧,并调整它们的大小,以确保它们的维度能被8整除。注意,我们显式地使用antialias=False
,因为这是这些模型的训练方式。然后我们使用捆绑到权重中的转换,以便对输入进行预处理,并将其值重新缩放到所需的[- 1,1]
区间。
from torchvision.models.optical_flow import Raft_Large_Weights
weights = Raft_Large_Weights.DEFAULT
transforms = weights.transforms()
def preprocess(img1_batch, img2_batch):
img1_batch = F.resize(img1_batch, size=[520, 960], antialias=False)
img2_batch = F.resize(img2_batch, size=[520, 960], antialias=False)
return transforms(img1_batch, img2_batch)
img1_batch, img2_batch = preprocess(img1_batch, img2_batch)
print(f"shape = {img1_batch.shape}, dtype = {img1_batch.dtype}")
type = <class 'list'>
length = 12 = number of iterations of the model
使用RAFT估计光流
我们将使用来自raft_large()
的RAFT实现,它遵循与原始论文中描述的相同的体系结构。我们还提供了raft_small()
模型构建器,它更小,运行速度更快,牺牲了一点精度。
from torchvision.models.optical_flow import raft_large
# If you can, run this example on a GPU, it will be a lot faster.
device = "cuda" if torch.cuda.is_available() else "cpu"
model = raft_large(weights=Raft_Large_Weights.DEFAULT, progress=False).to(device)
model = model.eval()
list_of_flows = model(img1_batch.to(device), img2_batch.to(device))
print(f"type = {type(list_of_flows)}")
print(f"length = {len(list_of_flows)} = number of iterations of the model")
RAFT模型输出预测流的列表,其中每个条目都是(N, 2, H, W)批预测流,对应于模型中的给定“iterations”。关于模型迭代特性的更多细节,请参考原文。在这里,我们只对最终预测的流感兴趣(它们是最准确的流),所以我们只检索列表中的最后一项。
如上所述,流是一个维度为(2,H, W)的张量(对于批量流来说是(N, 2, H, W)),其中每个条目对应于从第一张图像到第二张图像的每个像素的水平和垂直位移。注意,预测的流是以“像素”为单位的,它们不是归一化w.rt。图像的维度。
predicted_flows = list_of_flows[-1]
print(f"dtype = {predicted_flows.dtype}")
print(f"shape = {predicted_flows.shape} = (N, 2, H, W)")
print(f"min = {predicted_flows.min()}, max = {predicted_flows.max()}")
dtype = torch.float32
shape = torch.Size([2, 2, 520, 960]) = (N, 2, H, W)
min = -3.8997113704681396, max = 6.40040922164917
可视化预测的流
Torchvision提供了flow_to_image()
工具来将流转换为RGB图像。它还支持批量流。流中的每个“方向”都将映射到给定的RGB颜色。在下面的图像中,具有相似颜色的像素假设为模型向相似的方向移动。该模型正确地能够预测球和球员的运动。特别注意第一张图(向左)和第二张图(向上)中球的不同预测方向。
from torchvision.utils import flow_to_image
flow_imgs = flow_to_image(predicted_flows)
# The images have been mapped into [-1, 1] but for plotting we want them in [0, 1]
img1_batch = [(img1 + 1) / 2 for img1 in img1_batch]
grid = [[img1, flow_img] for (img1, flow_img) in zip(img1_batch, flow_imgs)]
plot(grid)
额外:创建流的GIF
在上面的例子中,我们只显示了2对帧的预测流。应用光流模型的一个有趣的方法是在整个视频上运行模型,并根据所有预测的流创建一个新视频。下面是一个片段,可以让你开始使用这个方法。我们注释掉了代码,因为这个例子是在没有GPU的机器上呈现的,运行它会花费太长时间。
# from torchvision.io import write_jpeg
# for i, (img1, img2) in enumerate(zip(frames, frames[1:])):
# # Note: it would be faster to predict batches of flows instead of individual flows
# img1, img2 = preprocess(img1, img2)
# list_of_flows = model(img1.to(device), img2.to(device))
# predicted_flow = list_of_flows[-1][0]
# flow_img = flow_to_image(predicted_flow).to("cpu")
# output_folder = "/tmp/" # Update this to the folder of your choice
# write_jpeg(flow_img, output_folder + f"predicted_flow_{i}.jpg")
一旦保存了.jpg流图像,您可以使用ffmpeg将它们转换为视频或GIF,例如:
ffmpeg -f image2 -framerate 30 -i predicted_flow_%d.jpg -loop -1 flow.gif
翻译自Pytorch官方文档OPTICAL FLOW: PREDICTING MOVEMENT WITH THE RAFT MODEL
标签:import,模型,flow,batch,flows,img2,光流,RAFT,img1 From: https://www.cnblogs.com/lfri/p/17216876.html