将 h264 字节字符串转换为 OpenCV 图像
Convert an h264 byte string to OpenCV images
在Python中,如何将h264字节字符串转换为OpenCV可以读取的图像,只保留最新图像?
长版:
大家好。
在 Python 工作,我试图从 adb screenrecord 获取输出,其方式允许我在需要时捕获帧并将其与 OpenCV 一起使用。据我了解,我需要不断读取流,因为它是 h264。
我已经尝试了多种方法来让它工作并得出结论,我需要寻求具体的帮助。
以下内容为我提供了所需的流,并且在我打印 stream.stdout.read(n) 时效果很好。
import subprocess as sp
adbCmd = ['adb', 'exec-out', 'screenrecord', '--output-format=h264', '-']
stream = sp.Popen(adbCmd, stdout = sp.PIPE, universal_newlines = True)
需要通用换行符才能在 Windows 上运行。
正在做:
sp.call(['ffplay', '-'], stdin = stream.stdout, universal_newlines = True)
有效。
问题是我现在正在尝试使用 ffmpeg 获取输入的 h264 流并输出尽可能多的帧,如果需要会覆盖最后一帧。
ffmpegCmd = ['ffmpeg', '-f', 'image2pipe', '-pix_fmt', 'bgr24', '-vcodec', 'h264', 'fps=30', '-']
ffmpeg = sp.Popen(ffmpegCmd, stdin = stream.stdout, stdout = sp.PIPE, universal_newlines = True)
这是我认为应该使用的,但我总是得到错误"Output file #0 does not contain any stream"。
编辑:
最终答案
原来 universal_newlines 选项破坏了行结尾并逐渐破坏了输出。另外,ffmpeg 命令错误,请参阅 LordNeckbeard 的回答。
这是正确的 ffmpeg 命令来实现所用的内容:
ffmpegCmd = ['ffmpeg', '-i', '-', '-f', 'rawvideo', '-vcodec', 'bmp', '-vf', 'fps=5', '-']
ffmpeg = sp.Popen(ffmpegCmd, stdin = stream.stdout, stdout = sp.PIPE)
然后将结果转换为 OpenCV 图像,您执行以下操作:
fileSizeBytes = ffmpeg.stdout.read(6)
fileSize = 0
for i in xrange(4):
fileSize += fileSizeBytes[i + 2] * 256 ** i
bmpData = fileSizeBytes + ffmpeg.stdout.read(fileSize - 6)
image = cv2.imdecode(np.fromstring(bmpData, dtype = np.uint8), 1)
这会将流的每一帧作为 OpenCV 图像。
使用其中任何一个:
ffmpeg -i - -pix_fmt bgr24 -f rawvideo -
ffmpeg -i pipe: -pix_fmt bgr24 -f rawvideo pipe:
ffmpeg -i pipe:0 -pix_fmt bgr24 -f rawvideo pipe:1
您没有提供太多关于输入的信息,因此您可能需要添加其他输入选项。
您没有指定您想要的输出格式,所以我只选择了rawvideo。您可以使用 ffmpeg -muxers
(或 ffmpeg -formats
,如果您的 ffmpeg
已过时)查看支持的输出格式(多路复用器)列表。不是所有的都适合做管道,比如MP4.
它运行良好,只是一个小改动:
这将循环读取流并每次显示最后一张图像
adbCmd = ['adb', 'exec-out', 'screenrecord', '--output-format=h264', '-']
stream = sp.Popen(adbCmd, stdout = sp.PIPE)
ffmpegCmd =['ffmpeg', '-i', '-', '-f', 'rawvideo', '-vf', 'scale=324:576',
'-vcodec', 'bmp', '-']
ffmpeg = sp.Popen(ffmpegCmd, stdin = stream.stdout, stdout = sp.PIPE)
while True:
fileSizeBytes = ffmpeg.stdout.read(6)
fileSize = 0
for i in xrange(4):
fileSize += array.array('B',fileSizeBytes[i + 2])[0] * 256 ** i
bmpData = fileSizeBytes + ffmpeg.stdout.read(fileSize - 6)
image = cv2.imdecode(np.fromstring(bmpData, dtype = np.uint8), 1)
cv2.imshow("im",image)
cv2.waitKey(25)
在Python中,如何将h264字节字符串转换为OpenCV可以读取的图像,只保留最新图像?
长版:
大家好。
在 Python 工作,我试图从 adb screenrecord 获取输出,其方式允许我在需要时捕获帧并将其与 OpenCV 一起使用。据我了解,我需要不断读取流,因为它是 h264。
我已经尝试了多种方法来让它工作并得出结论,我需要寻求具体的帮助。
以下内容为我提供了所需的流,并且在我打印 stream.stdout.read(n) 时效果很好。
import subprocess as sp
adbCmd = ['adb', 'exec-out', 'screenrecord', '--output-format=h264', '-']
stream = sp.Popen(adbCmd, stdout = sp.PIPE, universal_newlines = True)
需要通用换行符才能在 Windows 上运行。
正在做:
sp.call(['ffplay', '-'], stdin = stream.stdout, universal_newlines = True)
有效。
问题是我现在正在尝试使用 ffmpeg 获取输入的 h264 流并输出尽可能多的帧,如果需要会覆盖最后一帧。
ffmpegCmd = ['ffmpeg', '-f', 'image2pipe', '-pix_fmt', 'bgr24', '-vcodec', 'h264', 'fps=30', '-']
ffmpeg = sp.Popen(ffmpegCmd, stdin = stream.stdout, stdout = sp.PIPE, universal_newlines = True)
这是我认为应该使用的,但我总是得到错误"Output file #0 does not contain any stream"。
编辑:
最终答案
原来 universal_newlines 选项破坏了行结尾并逐渐破坏了输出。另外,ffmpeg 命令错误,请参阅 LordNeckbeard 的回答。
这是正确的 ffmpeg 命令来实现所用的内容:
ffmpegCmd = ['ffmpeg', '-i', '-', '-f', 'rawvideo', '-vcodec', 'bmp', '-vf', 'fps=5', '-']
ffmpeg = sp.Popen(ffmpegCmd, stdin = stream.stdout, stdout = sp.PIPE)
然后将结果转换为 OpenCV 图像,您执行以下操作:
fileSizeBytes = ffmpeg.stdout.read(6)
fileSize = 0
for i in xrange(4):
fileSize += fileSizeBytes[i + 2] * 256 ** i
bmpData = fileSizeBytes + ffmpeg.stdout.read(fileSize - 6)
image = cv2.imdecode(np.fromstring(bmpData, dtype = np.uint8), 1)
这会将流的每一帧作为 OpenCV 图像。
使用其中任何一个:
ffmpeg -i - -pix_fmt bgr24 -f rawvideo -
ffmpeg -i pipe: -pix_fmt bgr24 -f rawvideo pipe:
ffmpeg -i pipe:0 -pix_fmt bgr24 -f rawvideo pipe:1
您没有提供太多关于输入的信息,因此您可能需要添加其他输入选项。
您没有指定您想要的输出格式,所以我只选择了rawvideo。您可以使用
ffmpeg -muxers
(或ffmpeg -formats
,如果您的ffmpeg
已过时)查看支持的输出格式(多路复用器)列表。不是所有的都适合做管道,比如MP4.
它运行良好,只是一个小改动: 这将循环读取流并每次显示最后一张图像
adbCmd = ['adb', 'exec-out', 'screenrecord', '--output-format=h264', '-']
stream = sp.Popen(adbCmd, stdout = sp.PIPE)
ffmpegCmd =['ffmpeg', '-i', '-', '-f', 'rawvideo', '-vf', 'scale=324:576',
'-vcodec', 'bmp', '-']
ffmpeg = sp.Popen(ffmpegCmd, stdin = stream.stdout, stdout = sp.PIPE)
while True:
fileSizeBytes = ffmpeg.stdout.read(6)
fileSize = 0
for i in xrange(4):
fileSize += array.array('B',fileSizeBytes[i + 2])[0] * 256 ** i
bmpData = fileSizeBytes + ffmpeg.stdout.read(fileSize - 6)
image = cv2.imdecode(np.fromstring(bmpData, dtype = np.uint8), 1)
cv2.imshow("im",image)
cv2.waitKey(25)