简体   繁体   中英

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.

I've put a sleep of 50 ms, and specified a fps of 20.0 in the VideoWriter as following:

#!/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!!)

$ 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.

EDIT 1: I'm using python3, if that matters

EDIT 2: Using MJPG codec did solve the problem, (thanks @api55) so can someone tell me why XVID would give the incorrect fps?

Is it possible that XVID codec incorrectly writes the fps property, while the video is actually correctly coded in 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.

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='')

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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