ffmpeg 跑步数据图层 • 手艺
前面介绍了 Garmin VIRB,一款可以将运动数据图层叠加到视频上的小工具。
工具本身也算良心,简单、免费。
可惜,存在太多瑕疵:
•无法导入 1080p (MAC OSX 11.2.3)的原始视频
•导入视频如果重名,会覆盖原来的
•视频和 gpx 必须从一开始对齐,没有找到设置 offset 的地方,这就导致必须全程拍摄,不能分段叠加运动图层再剪辑
•每次 UI 操作比较费时间,似乎有模板功能,但没有尝试成功
•Gauge 的大小不知道怎么调整
•只能全程用一套 gauge 组合,不能做类似旋转木马这样的效果
•渲染比较慢,几乎是影片长度的 1/2,并且作为桌面软件,不方便做并发
目前尝试了几条片,感觉整个流程的时间成本过高。跑步一个小时左右的片,大概需要另外一个小时,才能完成后期编辑。
于是决定自己动手。
先准备好基底视频素材。
去 Strava 上下载 GPX。因为没有开 Garmin 的 Track 模式,这个漂移有点厉害。作为测试倒也是够了。
先试用 ffmpeg 的命令行,随手截一组图,来试试叠加图片。
ffmpeg -i base.mp4 -i overlay-sample/overlay01.png -filter_complex "[0:v][1:v] overlay=10:10:enable='between(t,1,2)'" output.mp4
检查一下叠加效果。
进一步叠加多条。
ffmpeg -i base.mp4 -i overlay-sample/overlay01.png -i overlay-sample/overlay02.png -filter_complex "[0:v][1:v] overlay=10:10:enable='between(t,5,10)' [tmp]; [tmp][2:v] overlay=500:20:enable='between(t,2,15)'" output.mp4
检查叠加效果。
接下来尝试用 Python 的 PIL 库自动生成图片。
from PIL import Image, ImageDraw
for seq in range(10):
img = Image.new('RGBA', (100, 30))
d = ImageDraw.Draw(img)
d.text((10,10), f"Time: {seq}", fill=(255,0,0))
img.save(f'overlay/overlay{seq:03d}.png')
先假装放一段时间文字在上面。
接着用 Python 来拼装 ffmpeg 的命令。
这个拼装过程需要格外注意参数和格式。经过几个步骤,最后输出了一条巨长无比的 ffmepg 命令。把命令直接贴进 Terminal 运行即可。
第一个系统性的试验成功。图片是加上去了,但由于视频很大,overlay 只占了一小块。
接着调整字号。
调整字号后的效果如图。
最后一步,就是把 gpx 文件内部的信息读取出来,然后写点逻辑排版 overlay。使用 gpxpy 这个库。
import gpxpy
import gpxpy.gpx
gpx_file = open(gpx_file_name, 'r')
gpx = gpxpy.parse(gpx_file)
points = []
for track in gpx.tracks:
for segment in track.segments:
for point in segment.points:
points.append(point)
第一版的结果如图:
到目前为止,已经可以看到 gpx 轨迹以及当前的座标了。
接下来就是各种细化:
•Overlay 的位置拜访
•gpx 到视频座标系的投影
•gpx 和视频串流对齐时间
•一些 PIL 的样式调整
得到的最终结果如图。
完整影片,可以到 Youtube 查看。
[no cut][1080p] Warm-up at A before speed test, 2 laps, 4 min[1]
目前算是完成原型。想到的进一步需求有:
•增加常用指标的 overlay component:距离、时间、爬升、心率、配速。
•响应式(responsive)的 overlay 设计
•根据视频文件元信息对齐 gpx 文件;也支持手动设置 offset
•基于上一条,支持一个 gpx 对应一组 footage,自动全加 overlay
•将 gpx 的 tracking points 插值(解决当前位置的跳跃问题;大约 2s 一个点)
•基于上一条,提高 overlay 层的 FPS (目前是 1 FPS)
•使用云技术将 overlay 的过程并发 (e.g. Apache beam/ GCP DataFlow)
•使用 Youtube resumable API[2] 上传大文件
•可以指定 Strava activity ID,直接拉取丰富数据
•可以指定 activity 使用的起止时间
•从 open street map 上,拉取简单的地图层做 background
•[1] [no cut][1080p] Warm-up at A before speed test, 2 laps, 4 min: https://www.youtube.com/watch?v=MVwVuyAwFFY
•[2] Youtube resumable API: https://developers.google.com/youtube/v3/guides/using_resumable_upload_protocol
•[3] https://www.titanwolf.org/Network/q/8006bfa5-a0a1-44e8-85b1-3ae3aac63936/x: https://www.titanwolf.org/Network/q/8006bfa5-a0a1-44e8-85b1-3ae3aac63936/x
•[4] https://www.geeksforgeeks.org/create-transparent-png-image-with-python-pillow/: https://www.geeksforgeeks.org/create-transparent-png-image-with-python-pillow/
•[5] https://stackoverflow.com/questions/4902198/pil-how-to-scale-text-size-in-relation-to-the-size-of-the-image: https://stackoverflow.com/questions/4902198/pil-how-to-scale-text-size-in-relation-to-the-size-of-the-image
博闻
|
明察
|
躬行
心法
|
手艺
|
随想