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.