【问题标题】:Getting very high fps for video stream captured and stored using opencv使用 opencv 捕获和存储的视频流获得非常高的 fps
【发布时间】:2018-01-26 08:34:33
【问题描述】:

我编写了一个小的 Python 代码,它从网络摄像头捕获视频流,并将其写入输出文件。

我已经休眠了 50 毫秒,并在 VideoWriter 中指定了 20.0 的 fps,如下所示:

#!/usr/bin/python
import cv2
from PIL import Image
import threading
from http.server import BaseHTTPRequestHandler,HTTPServer
from socketserver import ThreadingMixIn
from io import StringIO,BytesIO
import time
import datetime

capture=None
out=None

class CamHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path.endswith('.mjpg'):
            self.send_response(200)
            self.send_header('Content-type','multipart/x-mixed-replace; boundary=--jpgboundary')
            self.end_headers()
            while True:
                try:
                    rc,img = capture.read()
                    if not rc:
                        continue
                    #Get the timestamp on the frame
                    timestamp = datetime.datetime.now()
                    ts = timestamp.strftime("%A %d %B %Y %I:%M:%S%p")
                    cv2.putText(img, ts, (10, img.shape[0] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0, 0, 255), 1)
                    #Store the frame into the output file
                    out.write(img)
                    #Some processing before sending the frame to webserver
                    imgRGB=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
                    jpg = Image.fromarray(imgRGB)
                    tmpFile = BytesIO()
                    jpg.save(tmpFile,'JPEG')
                    self.wfile.write("--jpgboundary".encode())
                    self.send_header('Content-type','image/jpeg')
                    self.send_header('Content-length',str(tmpFile.getbuffer().nbytes))
                    self.end_headers()
                    jpg.save(self.wfile,'JPEG')
                    time.sleep(0.05)
                except KeyboardInterrupt:
                    break
            return
        if self.path.endswith('.html'):
            self.send_response(200)
            self.send_header('Content-type','text/html')
            self.end_headers()
            self.wfile.write('<html><head></head><body>'.encode())
            self.wfile.write('<img src="http://127.0.0.1:8080/cam.mjpg"/>'.encode())
            self.wfile.write('</body></html>'.encode())
            return


class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
    """Handle requests in a separate thread."""

def main():
    global capture
    global out
    capture = cv2.VideoCapture(0)

    # Define the codec and create VideoWriter object
    fourcc = cv2.VideoWriter_fourcc(*'XVID')
    out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480))

    global img
    try:
        server = ThreadedHTTPServer(('0.0.0.0', 8080), CamHandler)
        print( "server started")
        server.serve_forever()
    except KeyboardInterrupt:
        capture.release()
        server.socket.close()
        out.release()
        cv2.destroyAllWindows()

if __name__ == '__main__':
    main()

它工作正常,我可以保存视频。但是,在视频属性中看到的 fps 是 600.0(我设置的 30 倍!!)

$ mediainfo output.avi 
General
Complete name                            : output.avi
Format                                   : AVI
Format/Info                              : Audio Video Interleave
File size                                : 4.95 MiB
Duration                                 : 17s 252ms
Overall bit rate                         : 2 408 Kbps
Writing application                      : Lavf58.3.100

Video
ID                                       : 0
Format                                   : MPEG-4 Visual
Format profile                           : Simple@L1
Format settings, BVOP                    : No
Format settings, QPel                    : No
Format settings, GMC                     : No warppoints
Format settings, Matrix                  : Default (H.263)
Codec ID                                 : XVID
Codec ID/Hint                            : XviD
Duration                                 : 17s 252ms
Bit rate                                 : 2 290 Kbps
Width                                    : 640 pixels
Height                                   : 480 pixels
Display aspect ratio                     : 4:3
Frame rate                               : 600.000 fps
Color space                              : YUV
Chroma subsampling                       : 4:2:0
Bit depth                                : 8 bits
Scan type                                : Progressive
Compression mode                         : Lossy
Bits/(Pixel*Frame)                       : 0.012
Stream size                              : 4.71 MiB (95%)
Writing library                          : Lavc58.6.103

我很确定我的代码看起来没问题,如果有任何明显的错误,请告诉我。万一这很重要,我使用的是 ubuntu 操作系统,带有内置网络摄像头的华硕 X553M 笔记本电脑来运行上述内容。

编辑 1: 我正在使用 python3,如果这很重要的话

编辑 2: 使用 MJPG 编解码器确实解决了这个问题,(感谢@api55)所以有人能告诉我为什么 XVID 会给出不正确的 fps 吗?

是否有可能是 XVID 编解码器错误地写入了 fps 属性,而视频实际上以 20 fps 正确编码?

【问题讨论】:

  • 您确定它在延迟之前没有超出您的尝试范围吗?
  • 您是否尝试过使用不同的 FPS,例如15、25?你得到同样的结果吗?你试过另一个fourcc吗?您是否尝试过使用相同的代码但使用静态图像(比如说在 100 的循环中)而不是通过您的流程获取它?
  • 我认为只有cv2.VideoWriter中的fps参数设置了视频FPS属性,而sleep对视频FPS属性没有影响。我测试了代码,行是Frame rate : 20.000 fps
  • @Silencer:你能告诉我确切的代码吗?我正在使用 python3 仅供参考。
  • 只是好奇,网络摄像头 fps 是否可能导致这样的事情?

标签: python opencv video frame-rate


【解决方案1】:

您每 50 毫秒 + 处理时间获取帧,但将它们写入视频的延迟为 50 毫秒,因此它们将以更高的速度播放,比率 =(50+处理时间)/ 50 毫秒。

【讨论】:

  • 您能详细说明我是如何编写延迟 20 毫秒的视频的吗?
  • 对不起,我的错误,混淆了 ms 和 fps。我确定了答案。我觉得处理时间比较长。
  • 只是删除睡眠。捕获将自动等待,直到有新的帧可用。
  • 很容易测试这是否是问题:在没有任何处理/编码/睡眠的情况下将 N 图像捕获到数组/列表/缓冲区,然后将它们写入视频文件。只是为了测试。
【解决方案2】:

我有这个食谱,它和安德烈回答的很相似。 fps 非常接近预期。

cap = cv2.VideoCapture(capture) # 0 | filepath
fps = cap.get(cv2.CAP_PROP_FPS)
period = 1000 / fps

while cap.isOpened():
    start = time.time()

    success, frame = cap.read()
    if not success:
        if capture:
            break  # video
        continue  # cam

    # processing steps

    cv2.imshow('video (ESC to quit)', frame)
    processing_time = (time.time() - start) * 1000
    wait_ms = period - processing_time if period > processing_time else period
    if cv2.waitKey(int(wait_ms)) & 0xFF == 27:
        break
    end = (time.time() - start)
    print(f'FPS: {1.0 / end:.2f} (expected {fps:.2f})\r', end='')

【讨论】:

    猜你喜欢
    • 2010-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-07
    • 1970-01-01
    • 2011-11-18
    • 2014-01-29
    • 2016-01-09
    相关资源
    最近更新 更多