将遥测数据添加到视频 [python]
Add telemetry data to video [python]
我有一个数据框,其中一列包含图像路径,另一列包含速度。
id Cam4 speed roll
0 /cam4/0.jpg 6.178000 1.7
1 /cam4/1.jpg 9.910790 2.3
2 /cam4/2.jpg 17.286564 3.6
3 /cam4/3.jpg 19.000000 5.8
4 /cam4/4.jpg 19.000000 9.3
我想创建带有图像的视频,这样做时我还想将遥测数据动态显示为叠加层
创建视频不是问题,这个 python 代码可以帮助我做到这一点。
import ffmpeg
import pandas as pd
# List of JPEG files
jpeg_files = df.Cam4.to_list()
# Concatinating images to create video
process = ffmpeg.input('pipe:', r='20', f='jpeg_pipe').output('/tmp/video.mp4', vcodec='libx264').overwrite_output().run_async(pipe_stdin=True)
for in_file in jpeg_files:
with open(in_file, 'rb') as f:
jpeg_data = f.read()
process.stdin.write(jpeg_data)
process.stdin.close()
process.wait()
问题是随着帧的变化,我希望遥测数据显示为帧上的叠加层。那是我不知道 how/what 要做的事情。有人可以帮忙吗
似乎最好的选择是使用 OpenCV 读取图像,在图像上绘制数据,然后将图像作为原始视频帧写入 FFmpeg。
FFmpeg 支持叠加滤镜,您可以使用它来将一个图像放置在其他图像上,但是很难通过管道使用叠加滤镜,因为它需要两个输入流。
使用两个带管道的输入流需要使用“命名管道”——解决方案会很复杂...
我建议如下:
- 读取第一张图片以获取视频大小(分辨率)。
- 为
rawvideo
输入格式配置 FFmpeg。
使用原始视频时,我们还需要配置视频大小和像素格式。
视频大小为 cols x rows.
像素格式为 bgr24(匹配 OpenCV 像素格式)。
- 迭代 JPEG 文件列表。
- 使用OpenCV读取图像文件
该图像是一个形状为 (row, cols, 3) 的 NumPy 数组。
- 在图像上绘制数据。
代码示例绘制文件名。
(绘制漂亮的遥测数据超出了我的回答范围)。
- 将图像(带有数据)写入 FFmpeg 子进程的标准输入管道。
这是一个完整的代码示例:
import ffmpeg
import cv2
#import pandas as pd
# Build 10 synthetic images for testing: im001.jpg, im002.jpg, im003.jpg...
################################################################################
ffmpeg.input('testsrc=duration=10:size=192x108:rate=1', f='lavfi').output('im%03d.jpg').run()
################################################################################
# List of JPEG files
#jpeg_files = df.zed2.to_list()
# List of 10 images for testing
jpeg_files = ['im001.jpg', 'im002.jpg', 'im003.jpg', 'im004.jpg', 'im005.jpg', 'im006.jpg', 'im007.jpg', 'im008.jpg', 'im009.jpg', 'im010.jpg']
# Read the first image - just for getting the resolution.
img = cv2.imread(jpeg_files[0])
rows, cols = img.shape[0], img.shape[1]
# Concatenating images to create video - set input format to raw video
# Set the input pixel format to bgr24, and the video size to cols x rows
process = ffmpeg.input('pipe:', framerate='20', f='rawvideo', pixel_format='bgr24', s=f'{cols}x{rows}')\
.output('/tmp/video.mp4', vcodec='libx264', crf='17', pix_fmt='yuv420p')\
.overwrite_output().run_async(pipe_stdin=True)
for in_file in jpeg_files:
img = cv2.imread(in_file) # Read image using OpenCV
# Draw something (for testing)
img[(rows-30)//2:(rows+30)//2, 10:-10, :] = 60
cv2.putText(img, str(in_file), (cols//2-80, rows//2+10), cv2.FONT_HERSHEY_PLAIN, 2, (255, 30, 30), 2)
# Display image (for testing)
cv2.imshow('img', img)
cv2.waitKey(100)
# Write raw video frame to stdin pipe of FFmpeg sub-process.
process.stdin.write(img.tobytes())
process.stdin.close()
process.wait()
cv2.destroyAllWindows()
- 代码示例首先创建 10 张 JPEG 图像 - 用于测试代码。
- 示例显示图像以供测试。
示例视频帧:
我有一个数据框,其中一列包含图像路径,另一列包含速度。
id Cam4 speed roll
0 /cam4/0.jpg 6.178000 1.7
1 /cam4/1.jpg 9.910790 2.3
2 /cam4/2.jpg 17.286564 3.6
3 /cam4/3.jpg 19.000000 5.8
4 /cam4/4.jpg 19.000000 9.3
我想创建带有图像的视频,这样做时我还想将遥测数据动态显示为叠加层
创建视频不是问题,这个 python 代码可以帮助我做到这一点。
import ffmpeg
import pandas as pd
# List of JPEG files
jpeg_files = df.Cam4.to_list()
# Concatinating images to create video
process = ffmpeg.input('pipe:', r='20', f='jpeg_pipe').output('/tmp/video.mp4', vcodec='libx264').overwrite_output().run_async(pipe_stdin=True)
for in_file in jpeg_files:
with open(in_file, 'rb') as f:
jpeg_data = f.read()
process.stdin.write(jpeg_data)
process.stdin.close()
process.wait()
问题是随着帧的变化,我希望遥测数据显示为帧上的叠加层。那是我不知道 how/what 要做的事情。有人可以帮忙吗
似乎最好的选择是使用 OpenCV 读取图像,在图像上绘制数据,然后将图像作为原始视频帧写入 FFmpeg。
FFmpeg 支持叠加滤镜,您可以使用它来将一个图像放置在其他图像上,但是很难通过管道使用叠加滤镜,因为它需要两个输入流。
使用两个带管道的输入流需要使用“命名管道”——解决方案会很复杂...
我建议如下:
- 读取第一张图片以获取视频大小(分辨率)。
- 为
rawvideo
输入格式配置 FFmpeg。
使用原始视频时,我们还需要配置视频大小和像素格式。
视频大小为 cols x rows.
像素格式为 bgr24(匹配 OpenCV 像素格式)。 - 迭代 JPEG 文件列表。
- 使用OpenCV读取图像文件
该图像是一个形状为 (row, cols, 3) 的 NumPy 数组。 - 在图像上绘制数据。
代码示例绘制文件名。
(绘制漂亮的遥测数据超出了我的回答范围)。 - 将图像(带有数据)写入 FFmpeg 子进程的标准输入管道。
- 使用OpenCV读取图像文件
这是一个完整的代码示例:
import ffmpeg
import cv2
#import pandas as pd
# Build 10 synthetic images for testing: im001.jpg, im002.jpg, im003.jpg...
################################################################################
ffmpeg.input('testsrc=duration=10:size=192x108:rate=1', f='lavfi').output('im%03d.jpg').run()
################################################################################
# List of JPEG files
#jpeg_files = df.zed2.to_list()
# List of 10 images for testing
jpeg_files = ['im001.jpg', 'im002.jpg', 'im003.jpg', 'im004.jpg', 'im005.jpg', 'im006.jpg', 'im007.jpg', 'im008.jpg', 'im009.jpg', 'im010.jpg']
# Read the first image - just for getting the resolution.
img = cv2.imread(jpeg_files[0])
rows, cols = img.shape[0], img.shape[1]
# Concatenating images to create video - set input format to raw video
# Set the input pixel format to bgr24, and the video size to cols x rows
process = ffmpeg.input('pipe:', framerate='20', f='rawvideo', pixel_format='bgr24', s=f'{cols}x{rows}')\
.output('/tmp/video.mp4', vcodec='libx264', crf='17', pix_fmt='yuv420p')\
.overwrite_output().run_async(pipe_stdin=True)
for in_file in jpeg_files:
img = cv2.imread(in_file) # Read image using OpenCV
# Draw something (for testing)
img[(rows-30)//2:(rows+30)//2, 10:-10, :] = 60
cv2.putText(img, str(in_file), (cols//2-80, rows//2+10), cv2.FONT_HERSHEY_PLAIN, 2, (255, 30, 30), 2)
# Display image (for testing)
cv2.imshow('img', img)
cv2.waitKey(100)
# Write raw video frame to stdin pipe of FFmpeg sub-process.
process.stdin.write(img.tobytes())
process.stdin.close()
process.wait()
cv2.destroyAllWindows()
- 代码示例首先创建 10 张 JPEG 图像 - 用于测试代码。
- 示例显示图像以供测试。
示例视频帧: