简体   繁体   English

从 H264 流中提取每个单独的帧以使用 OpenCV 进行实时分析

[英]Extracting each individual frame from an H264 stream for real-time analysis with OpenCV

Problem Outline问题大纲

I have an h264 real-time video stream (I'll call this " the stream ") being captured in Process1.我在 Process1 中捕获了一个 h264 实时视频流(我称之为“”)。 My goal is to extract each frame from the stream as it comes through and use Process2 to analyze it with OpenCV.我的目标是从流中提取每个帧,并使用 Process2 用 OpenCV 对其进行分析。 (Process1 is nodejs, Process2 is Python) (Process1 是 nodejs,Process2 是 Python)

Things I've tried, and their failure modes:我尝试过的事情,以及他们的失败模式:

  • Send the stream directly from one Process1 to Process2 over a named fifo pipe :通过命名的 fifo 管道将流直接从 Process1 发送到 Process2

I succeeded in directing the stream from Process1 into the pipe.我成功地将来自 Process1 的流引导到管道中。 However, in Process2 (which is Python) I could not (a) extract individual frames from the stream, and (b) convert any extracted data from h264 into an OpenCV format (eg JPEG, numpy array).但是,在 Process2(它是 Python)中,我无法 (a) 从流中提取单个帧,以及 (b) 将从 h264 中提取的任何数据转换为 OpenCV 格式(例如 JPEG、numpy 数组)。

I had hoped to use OpenCV's VideoCapture() method, but it does not allow you to pass a FIFO pipe as an input.我曾希望使用 OpenCV 的 VideoCapture() 方法,但它不允许您将 FIFO 管道作为输入传递。 I was able to use VideoCapture by saving the h264 stream to a .h264 file, and then passing that as the file path.通过将 h264 流保存到 .h264 文件,然后将其作为文件路径传递,我能够使用 VideoCapture。 This doesn't help me, because I need to do my analysis in real time (ie I can't save the stream to a file before reading it in to OpenCV).这对我没有帮助,因为我需要实时进行分析(即我无法在将流读入 OpenCV 之前将其保存到文件中)。

  • Pipe the stream from Process1 to FFMPEG, use FFMPEG to change the stream format from h264 to MJPEG, then pipe the output to Process2 :将流从 Process1 传输到 FFMPEG,使用 FFMPEG 将流格式从 h264 更改为 MJPEG,然后将输出通过管道传输到 Process2

I attempted this using the command:我尝试使用以下命令:

cat pipeFromProcess1.fifo | cat pipeFromProcess1.fifo | ffmpeg -i pipe:0 -f h264 -f mjpeg pipe:1 | ffmpeg -i 管道:0 -f h264 -f mjpeg 管道:1 | cat > pipeToProcess2.fifo猫 > pipeToProcess2.fifo

The biggest issue with this approach is that FFMPEG takes inputs from Process1 until Process1 is killed, and only then does Process2 begin to receive the data.这种方法的最大问题是 FFMPEG 从 Process1 获取输入,直到 Process1 被杀死,然后 Process2 才开始接收数据。

Additionally, on the Process2 side, I still don't understand how to extract individual frames from the data coming over the pipe.此外,在 Process2 方面,我仍然不明白如何从来自管道的数据中提取单个帧。 I open the pipe for reading (as "f") and then execute data = f.readline().我打开管道进行读取(作为“f”),然后执行 data = f.readline()。 The size of data varies drastically (some reads have length on the order of 100, others length on the order of 1,000).数据的大小变化很大(一些读取的长度约为 100,其他的长度约为 1,000)。 When I use f.read() instead of f.readline(), the length is much larger, on the order of 100,000.当我使用 f.read() 而不是 f.readline() 时,长度要大得多,大约为 100,000。

If I were to know that I was getting the correct size chunk of data, I would still not know how to transform it into an OpenCV-compatible array because I don't understand the format it's coming over in. It's a string, but when I print it out it looks like this:如果我知道我得到了正确大小的数据块,我仍然不知道如何将它转换为 OpenCV 兼容的数组,因为我不明白它的格式。它是一个字符串,但是当我打印出来它看起来像这样:

_M~0A0 tQ,\\% e f/ H #Y p f# Kus } F ʳa G +$x %V }[ Wo 1'̶A c * &=Z^ o' Ͽ SX-ԁ涶V&H| $ ~ < E > u 7 cR f = 9 fs q ڄߧ 9v ] Ӷ & gr] n IRܜ 檯 + I w } 9 o w M m IJ m = Soՙ}S >j , ƙ ' tad =i WY FeC֓z 2 g ;EXX S Ҁ*, w _| & y H = ) Ɗ3@ h Ѻ Ɋ ZzR` ) y c ڋ. v !u S I# $9R Ԯ0py z 8 # A q ͕ ijc bp= ۹ c SqH _M~0A0 tQ,\\% e f/ H #Y p f# Kus } F ʳa G +$ x %V }[ Wo 1'̶A c * &=Z^ o' Ͽ SX-涶V&H| $ ~ < E > u 7 cR f = 9 fs q ڄ觇 9v ] Ӷ & gr】 n IR ✎台 + I w } 9 o w M m IJ m = Soՙ}S >j , ƙ ' tad =i WY FeC֓z 2 g ;EXX S Ҁ*, w _| & y H = ) Ɗ3@ h Ѻ Ɋ ZzR` ) y c ڋ. v !u S I# $9R Ԯ0py z 8 # A q ͕ ijc bp= ۹ c SqH

Converting from base64 doesn't seem to help.从 base64 转换似乎没有帮助。 I also tried:我也试过:

array = np.fromstring(data, dtype=np.uint8)

which does convert to an array, but not one of a size that makes sense based on the 640x368x3 dimensions of the frames I'm trying to decode.它确实转换为一个数组,但不是基于我试图解码的帧的 640x368x3 维度的一个有意义的大小。

  • Using decoders such as Broadway.js to convert the h264 stream :使用 Broadway.js 等解码器转换 h264 流

These seem to be focused on streaming to a website, and I did not have success trying to re-purpose them for my goal.这些似乎专注于流式传输到网站,我没有成功尝试将它们重新用于我的目标。

Clarification about what I'm NOT trying to do:澄清我不想做的事情:

I've found many related questions about streaming h264 video to a website.我发现了许多有关将 h264 视频流式传输到网站的相关问题。 This is a solved problem, but none of the solutions help me extract individual frames and put them in an OpenCV-compatible format.这是一个已解决的问题,但没有一个解决方案可以帮助我提取单个帧并将它们放入与 OpenCV 兼容的格式中。

Also, I need to use the extracted frames in real time on a continual basis.此外,我需要持续实时地使用提取的帧。 So saving each frame as a .jpg is not helpful.所以将每一帧保存为 .jpg 是没有帮助的。

System Specs系统规格

Raspberry Pi 3 running Raspian Jessie树莓派 3 运行 Raspian Jessie

Additional Detail附加细节

I've tried to generalize the problem I'm having in my question.我试图概括我在问题中遇到的问题。 If it's useful to know, Process1 is using the node-bebop package to pull down the h264 stream (using drone.getVideoStream()) from a Parrot Bebop 2.0.如果知道这很有用,Process1 正在使用 node-bebop 包从 Parrot Bebop 2.0 拉下 h264 流(使用drone.getVideoStream())。 I tried using the other video stream available through node-bebop (getMjpegStream()).我尝试使用通过 node-bebop (getMjpegStream()) 提供的其他视频流。 This worked, but was not nearly real-time;这行得通,但不是实时的; I was getting very intermittent data streams.我收到非常断断续续的数据流。 I've entered that specific problem as an Issue in the node-bebop repository.我已在 node-bebop 存储库中将该特定问题作为问题输入。

Thanks for reading;感谢阅读; I really appreciate any help anyone can give!我非常感谢任何人可以提供的任何帮助!

There are some suggestions online for piping the h264 stream into the opencv program using standard in:网上有一些使用标准将 h264 流传输到 opencv 程序的建议:

some-h264-stream | ./opencv-program

where opencv-program contains something like:其中 opencv-program 包含以下内容:

VideoCapture cap("/dev/stdin");

I was able to solve opening a Parrot Anafi stream with OpenCV (built with FFMPEG) in Python by setting the following environment variable:通过设置以下环境变量,我能够解决在 Python 中使用 OpenCV(使用 FFMPEG 构建)打开 Parrot Anafi 流的问题:

export OPENCV_FFMPEG_CAPTURE_OPTIONS="rtsp_transport;udp"

FFMPEG defaults to TCP transport, but the feed from the drone is UDP so this sets the correct mode for FFMPEG. FFMPEG 默认为 TCP 传输,但来自无人机的馈送是 UDP,因此这为 FFMPEG 设置了正确的模式。

Then use:然后使用:

cv2.VideoCapture(<stream URI>, cv2.CAP_FFMPEG)

ret, frame = cap.read()

while ret:
    cv2.imshow('frame', frame)
    # do other processing on frame...

    ret, frame = cap.read()
    if (cv2.waitKey(1) & 0xFF == ord('q')):
        break

cap.release()
cv2.destroyAllWindows()

as usual.像往常一样。

This should also work with a Parrot Bebop, but I don't have one to test it.这也应该适用于 Parrot Bebop,但我没有测试它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM