【发布时间】: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