简体   繁体   English

使用opencv捕获和存储的视频流获得非常高的fps

[英]Getting very high fps for video stream captured and stored using opencv

I've written a small python code, which captures video stream from the webcam, and writes it into an output file.我编写了一个小的 python 代码,它从网络摄像头捕获视频流,并将其写入输出文件。

I've put a sleep of 50 ms, and specified a fps of 20.0 in the VideoWriter as following:我已经休眠了 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()

It works fine, and I'm able to get the video saved.它工作正常,我能够保存视频。 However, the fps as seen in property of the video is 600.0 (30X what I set!!)但是,在视频属性中看到的 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

I'm pretty sure my code looks alright, do let me know if there are any obvious mistakes.我很确定我的代码看起来没问题,如果有任何明显的错误,请告诉我。 In case it matters, I'm using an ubuntu OS, Asus X553M laptop with inbuilt webcam to run the above.以防万一,我正在使用带有内置网络摄像头的 ubuntu 操作系统、华硕 X553M 笔记本电脑来运行上述内容。

EDIT 1: I'm using python3, if that matters编辑 1:我正在使用 python3,如果这很重要

EDIT 2: Using MJPG codec did solve the problem, (thanks @api55) so can someone tell me why XVID would give the incorrect fps?编辑 2:使用 MJPG 编解码器确实解决了问题,(感谢@api55)所以有人可以告诉我为什么 XVID 会给出不正确的 fps?

Is it possible that XVID codec incorrectly writes the fps property, while the video is actually correctly coded in 20 fps? XVID 编解码器是否可能错误地写入 fps 属性,而视频实际上以 20 fps 正确编码?

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

I have this recipe, it's pretty similar to what Andrey answered.我有这个食谱,它与安德烈回答的非常相似。 The fps gets pretty close to what's expected. 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='')

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

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